Update Settings Page components (#2986)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -1,181 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { Box, Tab, TabProps } from "@mui/material";
|
|
||||||
import { TabContext, TabList, TabPanel } from "@mui/lab";
|
|
||||||
import withStyles from "@mui/styles/withStyles";
|
|
||||||
import { Theme, useTheme } from "@mui/material/styles";
|
|
||||||
import createStyles from "@mui/styles/createStyles";
|
|
||||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
|
||||||
import { useLocation } from "react-router-dom";
|
|
||||||
|
|
||||||
export type TabItemProps = {
|
|
||||||
tabConfig: TabProps | any;
|
|
||||||
content?: JSX.Element | JSX.Element[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type VerticalTabsProps = {
|
|
||||||
classes: any;
|
|
||||||
children: TabItemProps[];
|
|
||||||
selectedTab?: string;
|
|
||||||
routes?: any;
|
|
||||||
isRouteTabs?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
tabsContainer: {
|
|
||||||
display: "flex",
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
},
|
|
||||||
tabsHeaderContainer: {
|
|
||||||
width: "300px",
|
|
||||||
background: "#F8F8F8",
|
|
||||||
borderRight: "1px solid #EAEAEA",
|
|
||||||
"& .MuiTabs-root": {
|
|
||||||
"& .MuiTabs-indicator": {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
"& .MuiTab-root": {
|
|
||||||
display: "flex",
|
|
||||||
flexFlow: "row",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
borderBottom: "1px solid #EAEAEA",
|
|
||||||
"& .MuiSvgIcon-root": {
|
|
||||||
marginRight: 8,
|
|
||||||
marginBottom: 0,
|
|
||||||
},
|
|
||||||
"&.Mui-selected": {
|
|
||||||
background: "#E5E5E5",
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"&. MuiTabs-scroller": {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabContentContainer: {
|
|
||||||
width: "100%",
|
|
||||||
"& .MuiTabPanel-root": {
|
|
||||||
height: "100%",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabPanel: {
|
|
||||||
height: "100%",
|
|
||||||
},
|
|
||||||
/*Below md breakpoint make it horizontal and style it for scrolling tabs*/
|
|
||||||
"@media (max-width: 900px)": {
|
|
||||||
tabsContainer: {
|
|
||||||
flexFlow: "column",
|
|
||||||
flexDirection: "column",
|
|
||||||
},
|
|
||||||
tabsHeaderContainer: {
|
|
||||||
width: "100%",
|
|
||||||
borderBottom: " 1px solid #EAEAEA",
|
|
||||||
"& .MuiTabs-root .MuiTabs-scroller .MuiButtonBase-root": {
|
|
||||||
borderBottom: " 0px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const tabStripStyle = {
|
|
||||||
minHeight: 60,
|
|
||||||
};
|
|
||||||
|
|
||||||
const VerticalTabs = ({
|
|
||||||
children,
|
|
||||||
classes,
|
|
||||||
selectedTab = "0",
|
|
||||||
routes,
|
|
||||||
isRouteTabs,
|
|
||||||
}: VerticalTabsProps) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
const { pathname = "" } = useLocation();
|
|
||||||
|
|
||||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down("md"));
|
|
||||||
|
|
||||||
const [value, setValue] = useState(selectedTab);
|
|
||||||
|
|
||||||
const headerList: TabProps[] = [];
|
|
||||||
const contentList: React.ReactNode[] = [];
|
|
||||||
useEffect(() => {
|
|
||||||
if (isRouteTabs) {
|
|
||||||
const tabConfigElement = children.find(
|
|
||||||
(item) => item.tabConfig.to === pathname,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tabConfigElement) {
|
|
||||||
setValue(tabConfigElement.tabConfig.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [isRouteTabs, children, pathname]);
|
|
||||||
|
|
||||||
if (!children) return null;
|
|
||||||
|
|
||||||
children.forEach((child) => {
|
|
||||||
headerList.push(child.tabConfig);
|
|
||||||
contentList.push(child.content);
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (event: React.SyntheticEvent, newValue: string) => {
|
|
||||||
setValue(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabContext value={`${value}`}>
|
|
||||||
<Box className={classes.tabsContainer}>
|
|
||||||
<Box className={classes.tabsHeaderContainer}>
|
|
||||||
<TabList
|
|
||||||
onChange={handleChange}
|
|
||||||
orientation={isSmallScreen ? "horizontal" : "vertical"}
|
|
||||||
variant={isSmallScreen ? "scrollable" : "standard"}
|
|
||||||
scrollButtons="auto"
|
|
||||||
className={classes.tabList}
|
|
||||||
>
|
|
||||||
{headerList.map((item, index) => {
|
|
||||||
if (item) {
|
|
||||||
return (
|
|
||||||
<Tab
|
|
||||||
className={classes.tabHeader}
|
|
||||||
key={`v-tab-${index}`}
|
|
||||||
value={`${index}`}
|
|
||||||
style={tabStripStyle}
|
|
||||||
{...item}
|
|
||||||
disableRipple
|
|
||||||
disableTouchRipple
|
|
||||||
focusRipple={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})}
|
|
||||||
</TabList>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Box className={classes.tabContentContainer}>
|
|
||||||
{!isRouteTabs
|
|
||||||
? contentList.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<TabPanel
|
|
||||||
classes={{ ...classes.tabPanel }}
|
|
||||||
key={`v-tab-p-${index}`}
|
|
||||||
value={`${index}`}
|
|
||||||
>
|
|
||||||
{item ? item : null}
|
|
||||||
</TabPanel>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
{isRouteTabs ? (
|
|
||||||
<div className={classes.tabPanel}>{routes}</div>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</TabContext>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withStyles(styles)(VerticalTabs);
|
|
||||||
@@ -15,27 +15,31 @@
|
|||||||
// 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, { Fragment, useCallback, useEffect, useState } from "react";
|
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||||
import { Theme } from "@mui/material/styles";
|
import {
|
||||||
import createStyles from "@mui/styles/createStyles";
|
Box,
|
||||||
import withStyles from "@mui/styles/withStyles";
|
Grid,
|
||||||
import Grid from "@mui/material/Grid";
|
HelpBox,
|
||||||
|
PageLayout,
|
||||||
|
ScreenTitle,
|
||||||
|
SettingsIcon,
|
||||||
|
Tabs,
|
||||||
|
} from "mds";
|
||||||
|
|
||||||
import { configurationElements } from "../utils";
|
import { configurationElements } from "../utils";
|
||||||
import {
|
import {
|
||||||
actionsTray,
|
Navigate,
|
||||||
containerForHeader,
|
Route,
|
||||||
searchField,
|
Routes,
|
||||||
} from "../../Common/FormComponents/common/styleLibrary";
|
useLocation,
|
||||||
import { HelpBox, PageLayout, SettingsIcon } from "mds";
|
useNavigate,
|
||||||
import { Link, Navigate, Route, Routes, useLocation } from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import VerticalTabs from "../../Common/VerticalTabs/VerticalTabs";
|
|
||||||
import ScreenTitle from "../../Common/ScreenTitle/ScreenTitle";
|
|
||||||
import ConfigurationForm from "./ConfigurationForm";
|
import ConfigurationForm from "./ConfigurationForm";
|
||||||
import { IAM_PAGES } from "../../../../common/SecureComponent/permissions";
|
import { IAM_PAGES } from "../../../../common/SecureComponent/permissions";
|
||||||
import PageHeaderWrapper from "../../Common/PageHeaderWrapper/PageHeaderWrapper";
|
import PageHeaderWrapper from "../../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||||
import ExportConfigButton from "./ExportConfigButton";
|
import ExportConfigButton from "./ExportConfigButton";
|
||||||
import ImportConfigButton from "./ImportConfigButton";
|
import ImportConfigButton from "./ImportConfigButton";
|
||||||
import { Box } from "@mui/material";
|
|
||||||
import HelpMenu from "../../HelpMenu";
|
import HelpMenu from "../../HelpMenu";
|
||||||
import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice";
|
import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice";
|
||||||
import { useAppDispatch } from "../../../../store";
|
import { useAppDispatch } from "../../../../store";
|
||||||
@@ -43,26 +47,6 @@ import { api } from "../../../../api";
|
|||||||
import { IElement } from "../types";
|
import { IElement } from "../types";
|
||||||
import { errorToHandler } from "../../../../api/errors";
|
import { errorToHandler } from "../../../../api/errors";
|
||||||
|
|
||||||
interface IConfigurationOptions {
|
|
||||||
classes: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
settingsOptionsContainer: {
|
|
||||||
display: "flex" as const,
|
|
||||||
flexDirection: "row" as const,
|
|
||||||
justifyContent: "flex-start" as const,
|
|
||||||
flexWrap: "wrap" as const,
|
|
||||||
border: "#E5E5E5 1px solid",
|
|
||||||
borderRadius: 2,
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
},
|
|
||||||
...searchField,
|
|
||||||
...actionsTray,
|
|
||||||
...containerForHeader,
|
|
||||||
});
|
|
||||||
|
|
||||||
const getRoutePath = (path: string) => {
|
const getRoutePath = (path: string) => {
|
||||||
return `${IAM_PAGES.SETTINGS}/${path}`;
|
return `${IAM_PAGES.SETTINGS}/${path}`;
|
||||||
};
|
};
|
||||||
@@ -71,9 +55,10 @@ const getRoutePath = (path: string) => {
|
|||||||
const NON_SUB_SYS_CONFIG_ITEMS = ["region"];
|
const NON_SUB_SYS_CONFIG_ITEMS = ["region"];
|
||||||
const IGNORED_CONFIG_SUB_SYS = ["cache"]; // cache config is not supported.
|
const IGNORED_CONFIG_SUB_SYS = ["cache"]; // cache config is not supported.
|
||||||
|
|
||||||
const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
const ConfigurationOptions = () => {
|
||||||
const { pathname = "" } = useLocation();
|
const { pathname = "" } = useLocation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [configSubSysList, setConfigSubSysList] = useState<string[]>([]);
|
const [configSubSysList, setConfigSubSysList] = useState<string[]>([]);
|
||||||
const fetchConfigSubSysList = useCallback(async () => {
|
const fetchConfigSubSysList = useCallback(async () => {
|
||||||
@@ -99,8 +84,6 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
|||||||
});
|
});
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
let selConfigTab = pathname.substring(pathname.lastIndexOf("/") + 1);
|
|
||||||
selConfigTab = selConfigTab === "settings" ? "region" : selConfigTab;
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConfigSubSysList();
|
fetchConfigSubSysList();
|
||||||
dispatch(setHelpName("settings_Region"));
|
dispatch(setHelpName("settings_Region"));
|
||||||
@@ -121,59 +104,57 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<PageHeaderWrapper label={"Settings"} actions={<HelpMenu />} />
|
<PageHeaderWrapper label={"Settings"} actions={<HelpMenu />} />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12} id={"settings-container"}>
|
||||||
<div
|
<ScreenTitle
|
||||||
id="settings-container"
|
icon={<SettingsIcon />}
|
||||||
className={classes.settingsOptionsContainer}
|
title={"MinIO Configuration:"}
|
||||||
>
|
actions={
|
||||||
<ScreenTitle
|
<Box
|
||||||
icon={<SettingsIcon />}
|
sx={{
|
||||||
title={"MinIO Configuration:"}
|
display: "flex",
|
||||||
actions={
|
gap: 10,
|
||||||
<Box
|
}}
|
||||||
sx={{
|
>
|
||||||
display: "flex",
|
<ImportConfigButton />
|
||||||
gap: 2,
|
<ExportConfigButton />
|
||||||
}}
|
</Box>
|
||||||
>
|
}
|
||||||
<ImportConfigButton />
|
sx={{ marginBottom: 15 }}
|
||||||
<ExportConfigButton />
|
/>
|
||||||
</Box>
|
<Tabs
|
||||||
}
|
currentTabOrPath={pathname}
|
||||||
/>
|
onTabClick={(path) => {
|
||||||
<VerticalTabs
|
navigate(path);
|
||||||
selectedTab={selConfigTab}
|
}}
|
||||||
isRouteTabs
|
useRouteTabs
|
||||||
routes={
|
options={availableConfigSubSys.map((element) => {
|
||||||
<Routes>
|
const { configuration_id, configuration_label, icon } = element;
|
||||||
{availableConfigSubSys.map((element) => (
|
return {
|
||||||
<Route
|
tabConfig: {
|
||||||
key={`configItem-${element.configuration_label}`}
|
id: `settings-tab-${configuration_label}`,
|
||||||
path={`${element.configuration_id}`}
|
label: configuration_label,
|
||||||
element={<ConfigurationForm />}
|
value: configuration_id,
|
||||||
/>
|
icon: icon,
|
||||||
))}
|
to: getRoutePath(configuration_id),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
routes={
|
||||||
|
<Routes>
|
||||||
|
{availableConfigSubSys.map((element) => (
|
||||||
<Route
|
<Route
|
||||||
path={"/"}
|
key={`configItem-${element.configuration_label}`}
|
||||||
element={<Navigate to={`${IAM_PAGES.SETTINGS}/region`} />}
|
path={`${element.configuration_id}`}
|
||||||
|
element={<ConfigurationForm />}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
))}
|
||||||
}
|
<Route
|
||||||
>
|
path={"/"}
|
||||||
{availableConfigSubSys.map((element) => {
|
element={<Navigate to={`${IAM_PAGES.SETTINGS}/region`} />}
|
||||||
const { configuration_id, configuration_label, icon } = element;
|
/>
|
||||||
return {
|
</Routes>
|
||||||
tabConfig: {
|
}
|
||||||
label: configuration_label,
|
/>
|
||||||
value: configuration_id,
|
|
||||||
icon: icon,
|
|
||||||
component: Link,
|
|
||||||
to: getRoutePath(configuration_id),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})}
|
|
||||||
</VerticalTabs>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sx={{ paddingTop: "15px" }}>
|
<Grid item xs={12} sx={{ paddingTop: "15px" }}>
|
||||||
<HelpBox
|
<HelpBox
|
||||||
@@ -203,4 +184,4 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withStyles(styles)(ConfigurationOptions);
|
export default ConfigurationOptions;
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2021 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, UploadIcon } from "mds";
|
import { Button, UploadIcon } from "mds";
|
||||||
import useApi from "../../Common/Hooks/useApi";
|
import useApi from "../../Common/Hooks/useApi";
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// This file is part of MinIO Console Server
|
||||||
|
// Copyright (c) 2021 MinIO, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Fragment, useEffect, useRef, useState } from "react";
|
import React, { Fragment, useEffect, useRef, useState } from "react";
|
||||||
import { Button, DownloadIcon } from "mds";
|
import { Button, DownloadIcon } from "mds";
|
||||||
import useApi from "../../Common/Hooks/useApi";
|
import useApi from "../../Common/Hooks/useApi";
|
||||||
|
|||||||
@@ -14,38 +14,27 @@
|
|||||||
// 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, { useEffect, useState } from "react";
|
import React, { Fragment, useEffect, useState } from "react";
|
||||||
import { Theme } from "@mui/material/styles";
|
|
||||||
import createStyles from "@mui/styles/createStyles";
|
|
||||||
import withStyles from "@mui/styles/withStyles";
|
|
||||||
import Grid from "@mui/material/Grid";
|
|
||||||
import { IElementValue, IOverrideEnv, KVField } from "../Configurations/types";
|
|
||||||
import {
|
import {
|
||||||
formFieldStyles,
|
CommentBox,
|
||||||
modalBasic,
|
ConsoleIcon,
|
||||||
} from "../Common/FormComponents/common/styleLibrary";
|
FormLayout,
|
||||||
|
Grid,
|
||||||
|
InputBox,
|
||||||
|
ReadBox,
|
||||||
|
Switch,
|
||||||
|
Tooltip,
|
||||||
|
} from "mds";
|
||||||
|
import { IElementValue, IOverrideEnv, KVField } from "../Configurations/types";
|
||||||
import CSVMultiSelector from "../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
import CSVMultiSelector from "../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
||||||
import CommentBoxWrapper from "../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
|
||||||
import PredefinedList from "../Common/FormComponents/PredefinedList/PredefinedList";
|
|
||||||
import { ConsoleIcon, InputBox, Switch, Tooltip } from "mds";
|
|
||||||
|
|
||||||
interface IConfGenericProps {
|
interface IConfGenericProps {
|
||||||
onChange: (newValue: IElementValue[]) => void;
|
onChange: (newValue: IElementValue[]) => void;
|
||||||
fields: KVField[];
|
fields: KVField[];
|
||||||
defaultVals?: IElementValue[];
|
defaultVals?: IElementValue[];
|
||||||
overrideEnv?: IOverrideEnv;
|
overrideEnv?: IOverrideEnv;
|
||||||
classes: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
...formFieldStyles,
|
|
||||||
formFieldRow: {
|
|
||||||
...formFieldStyles.formFieldRow,
|
|
||||||
},
|
|
||||||
...modalBasic,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Function to get defined values,
|
// Function to get defined values,
|
||||||
//we make this because the backed sometimes don't return all the keys when there is an initial configuration
|
//we make this because the backed sometimes don't return all the keys when there is an initial configuration
|
||||||
export const valueDef = (
|
export const valueDef = (
|
||||||
@@ -71,7 +60,6 @@ const ConfTargetGeneric = ({
|
|||||||
fields,
|
fields,
|
||||||
defaultVals,
|
defaultVals,
|
||||||
overrideEnv,
|
overrideEnv,
|
||||||
classes,
|
|
||||||
}: IConfGenericProps) => {
|
}: IConfGenericProps) => {
|
||||||
const [valueHolder, setValueHolder] = useState<IElementValue[]>([]);
|
const [valueHolder, setValueHolder] = useState<IElementValue[]>([]);
|
||||||
const fieldsElements = !fields ? [] : fields;
|
const fieldsElements = !fields ? [] : fields;
|
||||||
@@ -113,9 +101,8 @@ const ConfTargetGeneric = ({
|
|||||||
|
|
||||||
if (override) {
|
if (override) {
|
||||||
return (
|
return (
|
||||||
<PredefinedList
|
<ReadBox
|
||||||
label={field.label}
|
label={field.label}
|
||||||
content={override.value}
|
|
||||||
actionButton={
|
actionButton={
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
@@ -133,7 +120,10 @@ const ConfTargetGeneric = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
/>
|
sx={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{override.value}
|
||||||
|
</ReadBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,15 +170,13 @@ const ConfTargetGeneric = ({
|
|||||||
);
|
);
|
||||||
case "comment":
|
case "comment":
|
||||||
return (
|
return (
|
||||||
<CommentBoxWrapper
|
<CommentBox
|
||||||
id={field.name}
|
id={field.name}
|
||||||
name={field.name}
|
name={field.name}
|
||||||
label={field.label}
|
label={field.label}
|
||||||
tooltip={field.tooltip}
|
tooltip={field.tooltip}
|
||||||
value={holderItem ? holderItem.value : ""}
|
value={holderItem ? holderItem.value : ""}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e) => setValueElement(field.name, e.target.value, item)}
|
||||||
setValueElement(field.name, e.target.value, item)
|
|
||||||
}
|
|
||||||
placeholder={field.placeholder}
|
placeholder={field.placeholder}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -210,16 +198,12 @@ const ConfTargetGeneric = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container>
|
<FormLayout withBorders={false} containerPadding={false}>
|
||||||
<Grid xs={12} item className={classes.fieldBox}>
|
{fieldsElements.map((field, item) => (
|
||||||
{fieldsElements.map((field, item) => (
|
<Fragment key={field.name}>{fieldDefinition(field, item)}</Fragment>
|
||||||
<Grid item xs={12} key={field.name} className={classes.formFieldRow}>
|
))}
|
||||||
{fieldDefinition(field, item)}
|
</FormLayout>
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withStyles(styles)(ConfTargetGeneric);
|
export default ConfTargetGeneric;
|
||||||
|
|||||||
@@ -15,20 +15,13 @@
|
|||||||
// 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, { Fragment, useCallback, useEffect, useState } from "react";
|
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||||
import { Button, Loader } from "mds";
|
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import { Theme } from "@mui/material/styles";
|
import { Box, Button, Grid, Loader } from "mds";
|
||||||
import createStyles from "@mui/styles/createStyles";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import withStyles from "@mui/styles/withStyles";
|
import { useSelector } from "react-redux";
|
||||||
import { Box } from "@mui/material";
|
import { api } from "api";
|
||||||
import Grid from "@mui/material/Grid";
|
import { Configuration, ConfigurationKV } from "api/consoleApi";
|
||||||
import ConfTargetGeneric from "../ConfTargetGeneric";
|
import { errorToHandler } from "api/errors";
|
||||||
|
|
||||||
import {
|
|
||||||
fieldBasic,
|
|
||||||
settingsCommon,
|
|
||||||
} from "../../Common/FormComponents/common/styleLibrary";
|
|
||||||
import {
|
import {
|
||||||
fieldsConfigurations,
|
fieldsConfigurations,
|
||||||
overrideFields,
|
overrideFields,
|
||||||
@@ -40,7 +33,6 @@ import {
|
|||||||
IOverrideEnv,
|
IOverrideEnv,
|
||||||
KVField,
|
KVField,
|
||||||
} from "../../Configurations/types";
|
} from "../../Configurations/types";
|
||||||
import ResetConfigurationModal from "./ResetConfigurationModal";
|
|
||||||
import {
|
import {
|
||||||
configurationIsLoading,
|
configurationIsLoading,
|
||||||
setErrorSnackMessage,
|
setErrorSnackMessage,
|
||||||
@@ -50,31 +42,16 @@ import {
|
|||||||
} from "../../../../systemSlice";
|
} from "../../../../systemSlice";
|
||||||
import { AppState, useAppDispatch } from "../../../../store";
|
import { AppState, useAppDispatch } from "../../../../store";
|
||||||
import WebhookSettings from "../WebhookSettings/WebhookSettings";
|
import WebhookSettings from "../WebhookSettings/WebhookSettings";
|
||||||
import { useSelector } from "react-redux";
|
import ConfTargetGeneric from "../ConfTargetGeneric";
|
||||||
import { api } from "api";
|
import ResetConfigurationModal from "./ResetConfigurationModal";
|
||||||
import { Configuration, ConfigurationKV } from "api/consoleApi";
|
|
||||||
import { errorToHandler } from "api/errors";
|
|
||||||
|
|
||||||
const styles = (theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
...fieldBasic,
|
|
||||||
...settingsCommon,
|
|
||||||
settingsFormContainer: {
|
|
||||||
display: "grid",
|
|
||||||
gridTemplateColumns: "1fr",
|
|
||||||
gridGap: "10px",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
interface IAddNotificationEndpointProps {
|
interface IAddNotificationEndpointProps {
|
||||||
selectedConfiguration: IConfigurationElement;
|
selectedConfiguration: IConfigurationElement;
|
||||||
classes: any;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditConfiguration = ({
|
const EditConfiguration = ({
|
||||||
selectedConfiguration,
|
selectedConfiguration,
|
||||||
classes,
|
|
||||||
className = "",
|
className = "",
|
||||||
}: IAddNotificationEndpointProps) => {
|
}: IAddNotificationEndpointProps) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@@ -238,7 +215,15 @@ const EditConfiguration = ({
|
|||||||
flexFlow: "column",
|
flexFlow: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Grid item xs={12} className={classes.settingsFormContainer}>
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
sx={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "1fr",
|
||||||
|
gap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ConfTargetGeneric
|
<ConfTargetGeneric
|
||||||
fields={
|
fields={
|
||||||
fieldsConfigurations[
|
fieldsConfigurations[
|
||||||
@@ -263,6 +248,7 @@ const EditConfiguration = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
type={"button"}
|
||||||
id={"restore-defaults"}
|
id={"restore-defaults"}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={resetConfigurationMOpen}
|
onClick={resetConfigurationMOpen}
|
||||||
@@ -287,4 +273,4 @@ const EditConfiguration = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withStyles(styles)(EditConfiguration);
|
export default EditConfiguration;
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
// 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, { Fragment, useState } from "react";
|
import React, { Fragment, useState } from "react";
|
||||||
import { Button, Grid } from "mds";
|
import { Button, FormLayout, Grid, InputBox } from "mds";
|
||||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
import { api } from "api";
|
||||||
|
import { errorToHandler } from "api/errors";
|
||||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||||
import { Webhook } from "@mui/icons-material";
|
import { Webhook } from "@mui/icons-material";
|
||||||
import { formFieldStyles } from "../../Common/FormComponents/common/styleLibrary";
|
|
||||||
import CallToActionIcon from "@mui/icons-material/CallToAction";
|
import CallToActionIcon from "@mui/icons-material/CallToAction";
|
||||||
import PendingActionsIcon from "@mui/icons-material/PendingActions";
|
import PendingActionsIcon from "@mui/icons-material/PendingActions";
|
||||||
import {
|
import {
|
||||||
@@ -30,8 +30,7 @@ import {
|
|||||||
} from "../../../../systemSlice";
|
} from "../../../../systemSlice";
|
||||||
import { useAppDispatch } from "../../../../store";
|
import { useAppDispatch } from "../../../../store";
|
||||||
import { LinearProgress } from "@mui/material";
|
import { LinearProgress } from "@mui/material";
|
||||||
import { api } from "api";
|
import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary";
|
||||||
import { errorToHandler } from "api/errors";
|
|
||||||
|
|
||||||
interface IEndpointModal {
|
interface IEndpointModal {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -148,8 +147,8 @@ const AddEndpointModal = ({ open, type, onCloseEndpoint }: IEndpointModal) => {
|
|||||||
onClose={onCloseEndpoint}
|
onClose={onCloseEndpoint}
|
||||||
titleIcon={icon}
|
titleIcon={icon}
|
||||||
>
|
>
|
||||||
<Grid item xs={12} sx={{ ...formFieldStyles.formFieldRow }}>
|
<FormLayout containerPadding={false} withBorders={false}>
|
||||||
<InputBoxWrapper
|
<InputBox
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -167,9 +166,7 @@ const AddEndpointModal = ({ open, type, onCloseEndpoint }: IEndpointModal) => {
|
|||||||
pattern={"^(?=.*[a-zA-Z0-9]).{1,}$"}
|
pattern={"^(?=.*[a-zA-Z0-9]).{1,}$"}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</Grid>
|
<InputBox
|
||||||
<Grid item xs={12} sx={{ ...formFieldStyles.formFieldRow }}>
|
|
||||||
<InputBoxWrapper
|
|
||||||
id="endpoint"
|
id="endpoint"
|
||||||
name="endpoint"
|
name="endpoint"
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -190,9 +187,7 @@ const AddEndpointModal = ({ open, type, onCloseEndpoint }: IEndpointModal) => {
|
|||||||
}
|
}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</Grid>
|
<InputBox
|
||||||
<Grid item xs={12} sx={{ ...formFieldStyles.formFieldRow }}>
|
|
||||||
<InputBoxWrapper
|
|
||||||
id="auth-token"
|
id="auth-token"
|
||||||
name="auth-token"
|
name="auth-token"
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -202,7 +197,7 @@ const AddEndpointModal = ({ open, type, onCloseEndpoint }: IEndpointModal) => {
|
|||||||
label="Auth Token"
|
label="Auth Token"
|
||||||
value={authToken}
|
value={authToken}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</FormLayout>
|
||||||
{saving && (
|
{saving && (
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
@@ -214,14 +209,7 @@ const AddEndpointModal = ({ open, type, onCloseEndpoint }: IEndpointModal) => {
|
|||||||
<LinearProgress />
|
<LinearProgress />
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
<Grid
|
<Grid item xs={12} sx={modalStyleUtils.modalButtonBar}>
|
||||||
item
|
|
||||||
xs={12}
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
id={"reset"}
|
id={"reset"}
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -14,9 +14,10 @@
|
|||||||
// 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, { useEffect, useState } from "react";
|
import React, { useEffect, useState, Fragment } from "react";
|
||||||
import { ConfirmDeleteIcon } from "mds";
|
import { ConfirmDeleteIcon } from "mds";
|
||||||
import { DialogContentText } from "@mui/material";
|
import { api } from "api";
|
||||||
|
import { errorToHandler } from "api/errors";
|
||||||
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
import ConfirmDialog from "../../Common/ModalWrapper/ConfirmDialog";
|
||||||
import {
|
import {
|
||||||
configurationIsLoading,
|
configurationIsLoading,
|
||||||
@@ -24,8 +25,6 @@ import {
|
|||||||
setServerNeedsRestart,
|
setServerNeedsRestart,
|
||||||
} from "../../../../systemSlice";
|
} from "../../../../systemSlice";
|
||||||
import { useAppDispatch } from "../../../../store";
|
import { useAppDispatch } from "../../../../store";
|
||||||
import { api } from "api";
|
|
||||||
import { errorToHandler } from "api/errors";
|
|
||||||
|
|
||||||
interface IDeleteWebhookEndpoint {
|
interface IDeleteWebhookEndpoint {
|
||||||
modalOpen: boolean;
|
modalOpen: boolean;
|
||||||
@@ -38,7 +37,6 @@ const DeleteWebhookEndpoint = ({
|
|||||||
modalOpen,
|
modalOpen,
|
||||||
onClose,
|
onClose,
|
||||||
selectedARN,
|
selectedARN,
|
||||||
type,
|
|
||||||
}: IDeleteWebhookEndpoint) => {
|
}: IDeleteWebhookEndpoint) => {
|
||||||
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
|
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
@@ -84,10 +82,10 @@ const DeleteWebhookEndpoint = ({
|
|||||||
titleIcon={<ConfirmDeleteIcon />}
|
titleIcon={<ConfirmDeleteIcon />}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
confirmationContent={
|
confirmationContent={
|
||||||
<DialogContentText>
|
<Fragment>
|
||||||
{`${message} `}
|
{`${message} `}
|
||||||
<strong>{selectedARN}</strong>?
|
<strong>{selectedARN}</strong>?
|
||||||
</DialogContentText>
|
</Fragment>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,11 +43,10 @@ test("All vertical tab items exist", async (t) => {
|
|||||||
const settingsHealTabExists = elements.settingsHealTab.exists;
|
const settingsHealTabExists = elements.settingsHealTab.exists;
|
||||||
const settingsScannerTabExists = elements.settingsScannerTab.exists;
|
const settingsScannerTabExists = elements.settingsScannerTab.exists;
|
||||||
const settingsEtcdTabExists = elements.settingsEtcdTab.exists;
|
const settingsEtcdTabExists = elements.settingsEtcdTab.exists;
|
||||||
const settingsOpenIdTabExists = elements.settingsOpenIdTab.exists;
|
|
||||||
const settingsLdapTabExists = elements.settingsLdapTab.exists;
|
|
||||||
const settingsLoggerWebhookTabExists =
|
const settingsLoggerWebhookTabExists =
|
||||||
elements.settingsLoggerWebhookTab.exists;
|
elements.settingsLoggerWebhookTab.exists;
|
||||||
const settingsAuditWebhookTabExists = elements.settingsAuditWebhookTab.exists;
|
const settingsAuditWebhookTabExists = elements.settingsAuditWebhookTab.exists;
|
||||||
|
const settingsAuditKafkaTabExists = elements.settingsAuditKafkaTab.exists;
|
||||||
await t
|
await t
|
||||||
.navigateTo("http://localhost:9090/settings/configurations")
|
.navigateTo("http://localhost:9090/settings/configurations")
|
||||||
.expect(settingsRegionTabExists)
|
.expect(settingsRegionTabExists)
|
||||||
@@ -65,5 +64,7 @@ test("All vertical tab items exist", async (t) => {
|
|||||||
.expect(settingsLoggerWebhookTabExists)
|
.expect(settingsLoggerWebhookTabExists)
|
||||||
.ok()
|
.ok()
|
||||||
.expect(settingsAuditWebhookTabExists)
|
.expect(settingsAuditWebhookTabExists)
|
||||||
|
.ok()
|
||||||
|
.expect(settingsAuditKafkaTabExists)
|
||||||
.ok();
|
.ok();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -123,45 +123,41 @@ export const settingsWindow = Selector("#settings-container");
|
|||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
// Settings page vertical tabs
|
// Settings page vertical tabs
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
export const settingsRegionTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsRegionTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/region",
|
"settings-tab-Region",
|
||||||
);
|
);
|
||||||
export const settingsCompressionTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsCompressionTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/compression",
|
"settings-tab-Compression",
|
||||||
);
|
);
|
||||||
export const settingsApiTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsApiTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/api",
|
"settings-tab-API",
|
||||||
);
|
);
|
||||||
export const settingsHealTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsHealTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/heal",
|
"settings-tab-Heal",
|
||||||
);
|
);
|
||||||
export const settingsScannerTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsScannerTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/scanner",
|
"settings-tab-Scanner",
|
||||||
);
|
);
|
||||||
export const settingsEtcdTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsEtcdTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/etcd",
|
"settings-tab-Etcd",
|
||||||
);
|
);
|
||||||
export const settingsOpenIdTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsLoggerWebhookTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/identity_openid",
|
"settings-tab-Logger Webhook",
|
||||||
);
|
);
|
||||||
export const settingsLdapTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsAuditWebhookTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/identity_ldap",
|
"settings-tab-Audit Webhook",
|
||||||
);
|
);
|
||||||
export const settingsLoggerWebhookTab = Selector(".MuiTab-root").withAttribute(
|
export const settingsAuditKafkaTab = Selector("button").withAttribute(
|
||||||
"href",
|
"id",
|
||||||
"/settings/configurations/logger_webhook",
|
"settings-tab-Audit Kafka",
|
||||||
);
|
|
||||||
export const settingsAuditWebhookTab = Selector(".MuiTab-root").withAttribute(
|
|
||||||
"href",
|
|
||||||
"/settings/configurations/audit_webhook",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user