Fix spacing on Add tenant forms (#1895)

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2022-04-22 21:59:18 -07:00
committed by GitHub
parent 66df609d4a
commit 8a96d8d8a5
9 changed files with 1413 additions and 1350 deletions

View File

@@ -0,0 +1,29 @@
// 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 React from "react";
type Props = {};
const SectionH1: React.FC<Props> = ({ children }) => {
return (
<h1 style={{ margin: 0, marginBottom: ".8rem", fontSize: "1.3rem" }}>
{children}
</h1>
);
};
export default SectionH1;

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License // 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/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useCallback, useEffect, useState } from "react"; import React, { Fragment, useCallback, useEffect, useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
@@ -37,6 +37,7 @@ import InputBoxWrapper from "../../../Common/FormComponents/InputBoxWrapper/Inpu
import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper"; import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper";
import { ISecurityContext } from "../../types"; import { ISecurityContext } from "../../types";
import InputUnitMenu from "../../../Common/FormComponents/InputUnitMenu/InputUnitMenu"; import InputUnitMenu from "../../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import SectionH1 from "../../../Common/SectionH1";
interface IConfigureProps { interface IConfigureProps {
updateAddField: typeof updateAddField; updateAddField: typeof updateAddField;
@@ -250,274 +251,287 @@ const ConfigLogSearch = ({
return ( return (
<Paper className={classes.paperWrapper}> <Paper className={classes.paperWrapper}>
<div className={classes.headerElement}> <Grid container alignItems={"center"}>
<h3 className={classes.h3Section}>Audit Log</h3> <Grid item xs>
<span className={classes.descriptionText}> <SectionH1>Audit Log</SectionH1>
Audit log deploys a small PostgreSQL database and stores access logs
of all calls into the tenant.
</span>
</div>
<Grid item xs={12} className={classes.configSectionItem}>
<FormSwitchWrapper
value="logSearchConfig"
id="log-search-enabled"
name="log_search_enabled"
checked={logSearchEnabled}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchEnabled", checked);
}}
label={"Enabled"}
/>
</Grid>
{logSearchEnabled && (
<Grid xs={12} className={classes.logSearchEnabledFields}>
<Grid item xs={12}>
<SelectWrapper
id="log_search_storage_class"
name="log_search_storage_class"
onChange={(e: SelectChangeEvent<string>) => {
updateField(
"logSearchSelectedStorageClass",
e.target.value as string
);
}}
label="Log Search Storage Class"
value={logSearchSelectedStorageClass}
options={configureSTClasses}
disabled={configureSTClasses.length < 1}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<InputBoxWrapper
type="number"
id="log_search_volume_size"
name="log_search_volume_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchVolumeSize", e.target.value);
cleanValidation("log_search_volume_size");
}}
label="Storage Size"
overlayObject={
<InputUnitMenu
id={"size-unit"}
onUnitChange={() => {}}
unitSelected={"Gi"}
unitsList={[{ label: "Gi", value: "Gi" }]}
disabled={true}
/>
}
value={logSearchVolumeSize}
required
error={validationErrors["log_search_volume_size"] || ""}
min="0"
/>
</div>
</Grid>
<fieldset
className={`${classes.fieldGroup} ${classes.fieldSpaceTop}`}
>
<legend className={classes.descriptionText}>
SecurityContext for LogSearch
</legend>
<Grid item xs={12}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_runAsUser"
name="logSearch_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("logSearch_securityContext_runAsUser");
}}
label="Run As User"
value={logSearchSecurityContext.runAsUser}
required
error={
validationErrors["logSearch_securityContext_runAsUser"] ||
""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_runAsGroup"
name="logSearch_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation("logSearch_securityContext_runAsGroup");
}}
label="Run As Group"
value={logSearchSecurityContext.runAsGroup}
required
error={
validationErrors[
"logSearch_securityContext_runAsGroup"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_fsGroup"
name="logSearch_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("logSearch_securityContext_fsGroup");
}}
label="FsGroup"
value={logSearchSecurityContext.fsGroup}
required
error={
validationErrors["logSearch_securityContext_fsGroup"] ||
""
}
min="0"
/>
</div>
</div>
</Grid>
<br />
<Grid item xs={12}>
<div className={classes.multiContainer}>
<FormSwitchWrapper
value="logSearchSecurityContextRunAsNonRoot"
id="logSearch_securityContext_runAsNonRoot"
name="logSearch_securityContext_runAsNonRoot"
checked={logSearchSecurityContext.runAsNonRoot}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsNonRoot: checked,
});
}}
label={"Do not run as Root"}
/>
</div>
</Grid>
</fieldset>
<fieldset className={classes.fieldGroup}>
<legend className={classes.descriptionText}>
SecurityContext for PostgreSQL
</legend>
<Grid item xs={12}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_runAsUser"
name="postgres_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("postgres_securityContext_runAsUser");
}}
label="Run As User"
value={logSearchPostgresSecurityContext.runAsUser}
required
error={
validationErrors["postgres_securityContext_runAsUser"] ||
""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_runAsGroup"
name="postgres_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation("postgres_securityContext_runAsGroup");
}}
label="Run As Group"
value={logSearchPostgresSecurityContext.runAsGroup}
required
error={
validationErrors["postgres_securityContext_runAsGroup"] ||
""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_fsGroup"
name="postgres_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("postgres_securityContext_fsGroup");
}}
label="FsGroup"
value={logSearchPostgresSecurityContext.fsGroup}
required
error={
validationErrors["postgres_securityContext_fsGroup"] || ""
}
min="0"
/>
</div>
</div>
</Grid>
<br />
<Grid item xs={12}>
<div className={classes.multiContainer}>
<FormSwitchWrapper
value="postgresSecurityContextRunAsNonRoot"
id="postgres_securityContext_runAsNonRoot"
name="postgres_securityContext_runAsNonRoot"
checked={logSearchPostgresSecurityContext.runAsNonRoot}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsNonRoot: checked,
});
}}
label={"Do not run as Root"}
/>
</div>
</Grid>
</fieldset>
</Grid> </Grid>
)} <Grid item xs={4}>
<FormSwitchWrapper
value="enableLogging"
id="enableLogging"
name="enableLogging"
checked={logSearchEnabled}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchEnabled", checked);
}}
indicatorLabels={["Enabled", "Disabled"]}
/>
</Grid>
</Grid>
<Grid container spacing={1}>
<Grid item xs={12}>
<span className={classes.descriptionText}>
Deploys a small PostgreSQL database and stores access logs of all
calls into the tenant.
</span>
</Grid>
<Grid xs={12}>
<hr className={classes.hrClass} />
</Grid>
{logSearchEnabled && (
<Fragment>
<Grid item xs={12}>
<SelectWrapper
id="log_search_storage_class"
name="log_search_storage_class"
onChange={(e: SelectChangeEvent<string>) => {
updateField(
"logSearchSelectedStorageClass",
e.target.value as string
);
}}
label="Log Search Storage Class"
value={logSearchSelectedStorageClass}
options={configureSTClasses}
disabled={configureSTClasses.length < 1}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<InputBoxWrapper
type="number"
id="log_search_volume_size"
name="log_search_volume_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchVolumeSize", e.target.value);
cleanValidation("log_search_volume_size");
}}
label="Storage Size"
overlayObject={
<InputUnitMenu
id={"size-unit"}
onUnitChange={() => {}}
unitSelected={"Gi"}
unitsList={[{ label: "Gi", value: "Gi" }]}
disabled={true}
/>
}
value={logSearchVolumeSize}
required
error={validationErrors["log_search_volume_size"] || ""}
min="0"
/>
</div>
</Grid>
<fieldset
className={`${classes.fieldGroup} ${classes.fieldSpaceTop}`}
>
<legend className={classes.descriptionText}>
SecurityContext for LogSearch
</legend>
<Grid item xs={12}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_runAsUser"
name="logSearch_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("logSearch_securityContext_runAsUser");
}}
label="Run As User"
value={logSearchSecurityContext.runAsUser}
required
error={
validationErrors[
"logSearch_securityContext_runAsUser"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_runAsGroup"
name="logSearch_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation("logSearch_securityContext_runAsGroup");
}}
label="Run As Group"
value={logSearchSecurityContext.runAsGroup}
required
error={
validationErrors[
"logSearch_securityContext_runAsGroup"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="logSearch_securityContext_fsGroup"
name="logSearch_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("logSearch_securityContext_fsGroup");
}}
label="FsGroup"
value={logSearchSecurityContext.fsGroup}
required
error={
validationErrors["logSearch_securityContext_fsGroup"] ||
""
}
min="0"
/>
</div>
</div>
</Grid>
<br />
<Grid item xs={12}>
<div className={classes.multiContainer}>
<FormSwitchWrapper
value="logSearchSecurityContextRunAsNonRoot"
id="logSearch_securityContext_runAsNonRoot"
name="logSearch_securityContext_runAsNonRoot"
checked={logSearchSecurityContext.runAsNonRoot}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchSecurityContext", {
...logSearchSecurityContext,
runAsNonRoot: checked,
});
}}
label={"Do not run as Root"}
/>
</div>
</Grid>
</fieldset>
<fieldset className={classes.fieldGroup}>
<legend className={classes.descriptionText}>
SecurityContext for PostgreSQL
</legend>
<Grid item xs={12}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_runAsUser"
name="postgres_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("postgres_securityContext_runAsUser");
}}
label="Run As User"
value={logSearchPostgresSecurityContext.runAsUser}
required
error={
validationErrors[
"postgres_securityContext_runAsUser"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_runAsGroup"
name="postgres_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation("postgres_securityContext_runAsGroup");
}}
label="Run As Group"
value={logSearchPostgresSecurityContext.runAsGroup}
required
error={
validationErrors[
"postgres_securityContext_runAsGroup"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="postgres_securityContext_fsGroup"
name="postgres_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("postgres_securityContext_fsGroup");
}}
label="FsGroup"
value={logSearchPostgresSecurityContext.fsGroup}
required
error={
validationErrors["postgres_securityContext_fsGroup"] ||
""
}
min="0"
/>
</div>
</div>
</Grid>
<br />
<Grid item xs={12}>
<div className={classes.multiContainer}>
<FormSwitchWrapper
value="postgresSecurityContextRunAsNonRoot"
id="postgres_securityContext_runAsNonRoot"
name="postgres_securityContext_runAsNonRoot"
checked={logSearchPostgresSecurityContext.runAsNonRoot}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("logSearchPostgresSecurityContext", {
...logSearchPostgresSecurityContext,
runAsNonRoot: checked,
});
}}
label={"Do not run as Root"}
/>
</div>
</Grid>
</fieldset>
</Fragment>
)}
</Grid>
</Paper> </Paper>
); );
}; };

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License // 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/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useCallback, useEffect, useState } from "react"; import React, { Fragment, useCallback, useEffect, useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
@@ -37,6 +37,7 @@ import InputBoxWrapper from "../../../Common/FormComponents/InputBoxWrapper/Inpu
import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper"; import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper";
import { ISecurityContext } from "../../types"; import { ISecurityContext } from "../../types";
import InputUnitMenu from "../../../Common/FormComponents/InputUnitMenu/InputUnitMenu"; import InputUnitMenu from "../../../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import SectionH1 from "../../../Common/SectionH1";
interface IConfigureProps { interface IConfigureProps {
updateAddField: typeof updateAddField; updateAddField: typeof updateAddField;
@@ -219,176 +220,189 @@ const ConfigPrometheus = ({
return ( return (
<Paper className={classes.paperWrapper}> <Paper className={classes.paperWrapper}>
<div className={classes.headerElement}> <Grid container alignItems={"center"}>
<h3 className={classes.h3Section}>Monitoring</h3> <Grid item xs>
<SectionH1>Monitoring</SectionH1>
</Grid>
<Grid item xs={4}>
<FormSwitchWrapper
indicatorLabels={["Enabled", "Disabled"]}
checked={prometheusEnabled}
value={"monitoring_status"}
id="monitoring-status"
name="monitoring-status"
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("prometheusEnabled", checked);
}}
description=""
/>
</Grid>
</Grid>
<Grid item xs={12}>
<span className={classes.descriptionText}> <span className={classes.descriptionText}>
A small Prometheus will be deployed to keep metrics about the tenant. A small Prometheus will be deployed to keep metrics about the tenant.
</span> </span>
</div>
<Grid item xs={12} className={classes.configSectionItem}>
<FormSwitchWrapper
value="prometheusConfig"
id="prometheus_configuration"
name="prometheus_configuration"
checked={prometheusEnabled}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("prometheusEnabled", checked);
}}
label={"Enabled"}
/>
</Grid> </Grid>
{prometheusEnabled && ( <Grid xs={12}>
<Grid xs={12} className={classes.prometheusEnabledFields}> <hr className={classes.hrClass} />
<Grid item xs={12}> </Grid>
<SelectWrapper <Grid container spacing={1}>
id="prometheus_storage_class" {prometheusEnabled && (
name="prometheus_storage_class" <Fragment>
onChange={(e: SelectChangeEvent<string>) => { <Grid item xs={12}>
updateField( <SelectWrapper
"prometheusSelectedStorageClass", id="prometheus_storage_class"
e.target.value as string name="prometheus_storage_class"
); onChange={(e: SelectChangeEvent<string>) => {
}} updateField(
label="Prometheus Storage Class" "prometheusSelectedStorageClass",
value={prometheusSelectedStorageClass} e.target.value as string
options={configureSTClasses} );
disabled={configureSTClasses.length < 1}
/>
</Grid>
<Grid item xs={12}>
<div className={classes.multiContainer}>
<InputBoxWrapper
type="number"
id="prometheus_volume_size"
name="prometheus_volume_size"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusVolumeSize", e.target.value);
cleanValidation("prometheus_volume_size");
}} }}
label="Storage Size" label="Storage Class"
overlayObject={ value={prometheusSelectedStorageClass}
<InputUnitMenu options={configureSTClasses}
id={"size-unit"} disabled={configureSTClasses.length < 1}
onUnitChange={() => {}}
unitSelected={"Gi"}
unitsList={[{ label: "Gi", value: "Gi" }]}
disabled={true}
/>
}
value={prometheusVolumeSize}
required
error={validationErrors["prometheus_volume_size"] || ""}
min="0"
/> />
</div>
</Grid>
<fieldset
className={`${classes.fieldGroup} ${classes.fieldSpaceTop}`}
>
<legend className={classes.descriptionText}>
SecurityContext for Prometheus
</legend>
<Grid item xs={12} className={classes.configSectionItem}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_runAsUser"
name="prometheus_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("prometheus_securityContext_runAsUser");
}}
label="Run As User"
value={prometheusSecurityContext.runAsUser}
required
error={
validationErrors[
"prometheus_securityContext_runAsUser"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_runAsGroup"
name="prometheus_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation("prometheus_securityContext_runAsGroup");
}}
label="Run As Group"
value={prometheusSecurityContext.runAsGroup}
required
error={
validationErrors[
"prometheus_securityContext_runAsGroup"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_fsGroup"
name="prometheus_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("prometheus_securityContext_fsGroup");
}}
label="FsGroup"
value={prometheusSecurityContext.fsGroup}
required
error={
validationErrors["prometheus_securityContext_fsGroup"] ||
""
}
min="0"
/>
</div>
</div>
</Grid> </Grid>
<Grid item xs={12} className={classes.configSectionItem}> <Grid item xs={12}>
<div <div className={classes.multiContainer}>
className={`${classes.multiContainer} ${classes.fieldSpaceTop}`} <InputBoxWrapper
> type="number"
<FormSwitchWrapper id="prometheus_volume_size"
value="prometheusSecurityContextRunAsNonRoot" name="prometheus_volume_size"
id="prometheus_securityContext_runAsNonRoot" onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
name="prometheus_securityContext_runAsNonRoot" updateField("prometheusVolumeSize", e.target.value);
checked={prometheusSecurityContext.runAsNonRoot} cleanValidation("prometheus_volume_size");
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsNonRoot: checked,
});
}} }}
label={"Do not run as Root"} label="Storage Size"
overlayObject={
<InputUnitMenu
id={"size-unit"}
onUnitChange={() => {}}
unitSelected={"Gi"}
unitsList={[{ label: "Gi", value: "Gi" }]}
disabled={true}
/>
}
value={prometheusVolumeSize}
required
error={validationErrors["prometheus_volume_size"] || ""}
min="0"
/> />
</div> </div>
</Grid> </Grid>
</fieldset> <fieldset
</Grid> className={`${classes.fieldGroup} ${classes.fieldSpaceTop}`}
)} >
<legend className={classes.descriptionText}>
SecurityContext
</legend>
<Grid item xs={12} className={classes.configSectionItem}>
<div
className={`${classes.multiContainer} ${classes.responsiveSectionItem}`}
>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_runAsUser"
name="prometheus_securityContext_runAsUser"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsUser: e.target.value,
});
cleanValidation("prometheus_securityContext_runAsUser");
}}
label="Run As User"
value={prometheusSecurityContext.runAsUser}
required
error={
validationErrors[
"prometheus_securityContext_runAsUser"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_runAsGroup"
name="prometheus_securityContext_runAsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsGroup: e.target.value,
});
cleanValidation(
"prometheus_securityContext_runAsGroup"
);
}}
label="Run As Group"
value={prometheusSecurityContext.runAsGroup}
required
error={
validationErrors[
"prometheus_securityContext_runAsGroup"
] || ""
}
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
id="prometheus_securityContext_fsGroup"
name="prometheus_securityContext_fsGroup"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
fsGroup: e.target.value,
});
cleanValidation("prometheus_securityContext_fsGroup");
}}
label="FsGroup"
value={prometheusSecurityContext.fsGroup}
required
error={
validationErrors[
"prometheus_securityContext_fsGroup"
] || ""
}
min="0"
/>
</div>
</div>
</Grid>
<Grid item xs={12} className={classes.configSectionItem}>
<div
className={`${classes.multiContainer} ${classes.fieldSpaceTop}`}
>
<FormSwitchWrapper
value="prometheusSecurityContextRunAsNonRoot"
id="prometheus_securityContext_runAsNonRoot"
name="prometheus_securityContext_runAsNonRoot"
checked={prometheusSecurityContext.runAsNonRoot}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("prometheusSecurityContext", {
...prometheusSecurityContext,
runAsNonRoot: checked,
});
}}
label={"Do not run as Root"}
/>
</div>
</Grid>
</fieldset>
</Fragment>
)}
</Grid>
</Paper> </Paper>
); );
}; };

View File

@@ -19,7 +19,7 @@ import { connect } from "react-redux";
import { Theme } from "@mui/material/styles"; import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles"; import withStyles from "@mui/styles/withStyles";
import { Grid, IconButton, Paper, Typography } from "@mui/material"; import { Grid, IconButton, Paper } from "@mui/material";
import { import {
createTenantCommon, createTenantCommon,
modalBasic, modalBasic,
@@ -41,6 +41,7 @@ import FormSwitchWrapper from "../../../Common/FormComponents/FormSwitchWrapper/
import FileSelector from "../../../Common/FormComponents/FileSelector/FileSelector"; import FileSelector from "../../../Common/FormComponents/FileSelector/FileSelector";
import AddIcon from "../../../../../icons/AddIcon"; import AddIcon from "../../../../../icons/AddIcon";
import RemoveIcon from "../../../../../icons/RemoveIcon"; import RemoveIcon from "../../../../../icons/RemoveIcon";
import SectionTitle from "../../../Common/SectionTitle";
interface ISecurityProps { interface ISecurityProps {
classes: any; classes: any;
@@ -174,117 +175,158 @@ const Security = ({
<div className={classes.headerElement}> <div className={classes.headerElement}>
<h3 className={classes.h3Section}>Security</h3> <h3 className={classes.h3Section}>Security</h3>
</div> </div>
<Grid item xs={12}> <Grid container spacing={1}>
<FormSwitchWrapper <Grid item xs={12}>
value="enableTLS" <FormSwitchWrapper
id="enableTLS" value="enableTLS"
name="enableTLS" id="enableTLS"
checked={enableTLS} name="enableTLS"
onChange={(e) => { checked={enableTLS}
const targetD = e.target; onChange={(e) => {
const checked = targetD.checked; const targetD = e.target;
const checked = targetD.checked;
updateField("enableTLS", checked); updateField("enableTLS", checked);
}} }}
label={"Enable TLS"} label={"TLS"}
/> description={
Enable TLS for the tenant, this is required for Encryption Configuration "Securing all the traffic using TLS. This is required for Encryption Configuration"
}
/>
</Grid>
{enableTLS && ( {enableTLS && (
<Fragment> <Fragment>
<br /> <Grid item xs={12}>
<br /> <FormSwitchWrapper
<Typography variant="caption" display="block" gutterBottom> value="enableAutoCert"
AutoCert: MinIO Operator will generate all TLS certificates id="enableAutoCert"
automatically name="enableAutoCert"
</Typography> checked={enableAutoCert}
<Typography variant="caption" display="block" gutterBottom> onChange={(e) => {
Custom certificates: Allow user to provide your own certificates const targetD = e.target;
</Typography> const checked = targetD.checked;
<br /> updateField("enableAutoCert", checked);
</Fragment> }}
)} label={"AutoCert"}
</Grid> description={
{enableTLS && ( "The internode certificates will be generated and managed by MinIO Operator"
<Fragment> }
<Grid item xs={12}> />
<FormSwitchWrapper </Grid>
value="enableAutoCert" <Grid item xs={12}>
id="enableAutoCert" <FormSwitchWrapper
name="enableAutoCert" value="enableCustomCerts"
checked={enableAutoCert} id="enableCustomCerts"
onChange={(e) => { name="enableCustomCerts"
const targetD = e.target; checked={enableCustomCerts}
const checked = targetD.checked; onChange={(e) => {
const targetD = e.target;
updateField("enableAutoCert", checked); const checked = targetD.checked;
}} updateField("enableCustomCerts", checked);
label={"Enable AutoCert"} }}
/> label={"Custom Certificates"}
<FormSwitchWrapper description={"Certificates used to terminated TLS at MinIO"}
value="enableCustomCerts" />
id="enableCustomCerts" </Grid>
name="enableCustomCerts" {enableCustomCerts && (
checked={enableCustomCerts} <Fragment>
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
updateField("enableCustomCerts", checked);
}}
label={"Custom Certificates"}
/>
</Grid>
{enableCustomCerts && (
<Fragment>
<Grid container>
<Grid item xs={12} className={classes.minioCertsContainer}> <Grid item xs={12} className={classes.minioCertsContainer}>
<fieldset className={classes.fieldGroup}> <SectionTitle>MinIO Certificates</SectionTitle>
<legend className={classes.descriptionText}> {minioCertificates.map((keyPair: KeyPair) => (
MinIO Certificates <Grid
</legend> item
{minioCertificates.map((keyPair: KeyPair) => ( xs={12}
<Grid key={`minio-certs-${keyPair.id}`}
item className={classes.minioCertificateRows}
xs={12} >
key={`minio-certs-${keyPair.id}`} <Grid item xs={10} className={classes.fileItem}>
className={classes.minioCertificateRows} <FileSelector
> onChange={(encodedValue, fileName) => {
<Grid item xs={10} className={classes.fileItem}> addFileToKeyPair(
<FileSelector keyPair.id,
onChange={(encodedValue, fileName) => { "cert",
addFileToKeyPair( fileName,
keyPair.id, encodedValue
"cert", );
fileName, }}
encodedValue accept=".cer,.crt,.cert,.pem"
); id="tlsCert"
}} name="tlsCert"
accept=".cer,.crt,.cert,.pem" label="Cert"
id="tlsCert" value={keyPair.cert}
name="tlsCert" />
label="Cert" <FileSelector
value={keyPair.cert} onChange={(encodedValue, fileName) => {
/> addFileToKeyPair(
<FileSelector keyPair.id,
onChange={(encodedValue, fileName) => { "key",
addFileToKeyPair( fileName,
keyPair.id, encodedValue
"key", );
fileName, }}
encodedValue accept=".key,.pem"
); id="tlsKey"
}} name="tlsKey"
accept=".key,.pem" label="Key"
id="tlsKey" value={keyPair.key}
name="tlsKey" />
label="Key" </Grid>
value={keyPair.key}
/>
</Grid>
<Grid item xs={2} className={classes.rowActions}> <Grid item xs={2} className={classes.rowActions}>
<div className={classes.overlayAction}>
<IconButton size={"small"} onClick={addKeyPair}>
<AddIcon />
</IconButton>
</div>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() => {
deleteKeyPair(keyPair.id);
}}
>
<RemoveIcon />
</IconButton>
</div>
</Grid>
</Grid>
))}
</Grid>
<Grid item xs={12} className={classes.minioCertsContainer}>
<SectionTitle>MinIO CA Certificates</SectionTitle>
{caCertificates.map((keyPair: KeyPair) => (
<Grid
item
xs={12}
key={`minio-CA-certs-${keyPair.id}`}
className={classes.minioCACertsRow}
>
<Grid item xs={6}>
<FileSelector
onChange={(encodedValue, fileName) => {
addFileToCaCertificates(
keyPair.id,
"cert",
fileName,
encodedValue
);
}}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
</Grid>
<Grid item xs={6}>
<div className={classes.rowActions}>
<div className={classes.overlayAction}> <div className={classes.overlayAction}>
<IconButton size={"small"} onClick={addKeyPair}> <IconButton
size={"small"}
onClick={addCaCertificate}
>
<AddIcon /> <AddIcon />
</IconButton> </IconButton>
</div> </div>
@@ -292,81 +334,22 @@ const Security = ({
<IconButton <IconButton
size={"small"} size={"small"}
onClick={() => { onClick={() => {
deleteKeyPair(keyPair.id); deleteCaCertificate(keyPair.id);
}} }}
> >
<RemoveIcon /> <RemoveIcon />
</IconButton> </IconButton>
</div> </div>
</Grid> </div>
</Grid> </Grid>
))} </Grid>
</fieldset> ))}
</Grid> </Grid>
</Grid> </Fragment>
)}
<Grid container> </Fragment>
<Grid item xs={12} className={classes.minioCertsContainer}> )}
<fieldset className={classes.fieldGroup}> </Grid>
<legend className={classes.descriptionText}>
MinIO CA Certificates
</legend>
{caCertificates.map((keyPair: KeyPair) => (
<Grid
item
xs={12}
key={`minio-CA-certs-${keyPair.id}`}
className={classes.minioCACertsRow}
>
<Grid item xs={6}>
<FileSelector
onChange={(encodedValue, fileName) => {
addFileToCaCertificates(
keyPair.id,
"cert",
fileName,
encodedValue
);
}}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
</Grid>
<Grid item xs={6}>
<div className={classes.rowActions}>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={addCaCertificate}
>
<AddIcon />
</IconButton>
</div>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() => {
deleteCaCertificate(keyPair.id);
}}
>
<RemoveIcon />
</IconButton>
</div>
</div>
</Grid>
</Grid>
))}
</fieldset>
</Grid>
</Grid>
</Fragment>
)}
</Fragment>
)}
</Paper> </Paper>
); );
}; };

View File

@@ -582,7 +582,7 @@ const TenantDetails = ({
}} }}
{{ {{
tabConfig: { tabConfig: {
label: "Logging", label: "Audit Log",
value: "logging", value: "logging",
component: Link, component: Link,
to: getRoutePath("logging"), to: getRoutePath("logging"),

View File

@@ -683,28 +683,28 @@ const TenantEncryption = ({
return ( return (
<React.Fragment> <React.Fragment>
{confirmOpen && (
<ConfirmDialog
isOpen={confirmOpen}
title={
encryptionEnabled
? "Enable encryption at rest for tenant?"
: "Disable encryption at rest for tenant?"
}
confirmText={encryptionEnabled ? "Enable" : "Disable"}
cancelText="Cancel"
onClose={() => setConfirmOpen(false)}
onConfirm={updateEncryptionConfiguration}
confirmationContent={
<DialogContentText>
{encryptionEnabled
? "Data will be encrypted using and external KMS"
: "Current encrypted information will not be accessible"}
</DialogContentText>
}
/>
)}
<Grid container spacing={1}> <Grid container spacing={1}>
{confirmOpen && (
<ConfirmDialog
isOpen={confirmOpen}
title={
encryptionEnabled
? "Enable encryption at rest for tenant?"
: "Disable encryption at rest for tenant?"
}
confirmText={encryptionEnabled ? "Enable" : "Disable"}
cancelText="Cancel"
onClose={() => setConfirmOpen(false)}
onConfirm={updateEncryptionConfiguration}
confirmationContent={
<DialogContentText>
{encryptionEnabled
? "Data will be encrypted using and external KMS"
: "Current encrypted information will not be accessible"}
</DialogContentText>
}
/>
)}
<Grid item xs> <Grid item xs>
<h1 className={classes.sectionTitle}>Encryption</h1> <h1 className={classes.sectionTitle}>Encryption</h1>
</Grid> </Grid>

View File

@@ -29,14 +29,13 @@ import Grid from "@mui/material/Grid";
import { DialogContentText } from "@mui/material"; import { DialogContentText } from "@mui/material";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import api from "../../../../common/api"; import api from "../../../../common/api";
import { ITenant } from "../ListTenants/types"; import { ITenant, ITenantLogsStruct } from "../ListTenants/types";
import { AppState } from "../../../../store"; import { AppState } from "../../../../store";
import { ErrorResponseHandler } from "../../../../common/types"; import { ErrorResponseHandler } from "../../../../common/types";
import { EditIcon } from "../../../../icons"; import { EditIcon } from "../../../../icons";
import { setErrorSnackMessage } from "../../../../actions"; import { setErrorSnackMessage } from "../../../../actions";
import EditTenantLogsModal from "./EditTenantLogsModal"; import EditTenantLogsModal from "./EditTenantLogsModal";
import KeyPairView from "./KeyPairView"; import KeyPairView from "./KeyPairView";
import { ITenantLogsStruct } from "../ListTenants/types";
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog"; import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper"; import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton"; import RBIconButton from "../../Buckets/BucketDetails/SummaryItems/RBIconButton";
@@ -209,7 +208,7 @@ const TenantLogging = ({
)} )}
<Grid container alignItems={"center"}> <Grid container alignItems={"center"}>
<Grid item xs> <Grid item xs>
<h1 className={classes.sectionTitle}>Logging</h1> <h1 className={classes.sectionTitle}>Audit Log</h1>
</Grid> </Grid>
<Grid item xs={4}> <Grid item xs={4}>
<FormSwitchWrapper <FormSwitchWrapper

View File

@@ -52,7 +52,7 @@ test("Create Tenant Without Audit Log", async (t) => {
.click("#confirm-ok") .click("#confirm-ok")
.wait(1000) .wait(1000)
.click("#wizard-step-audit-log") .click("#wizard-step-audit-log")
.click("#log-search-enabled") .click("#enableLogging")
.click("#wizard-button-Create") .click("#wizard-button-Create")
.wait(1000) .wait(1000)
.click("#close") .click("#close")