From 72bb9d0ca18231f12c840cfc292af50454a193af Mon Sep 17 00:00:00 2001 From: Alex <33497058+bexsoft@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:30:42 -0600 Subject: [PATCH] Update Settings Page components (#2986) Signed-off-by: Benjamin Perez --- .../Common/VerticalTabs/VerticalTabs.tsx | 181 ------------------ .../ConfigurationOptions.tsx | 157 +++++++-------- .../ExportConfigButton.tsx | 16 ++ .../ImportConfigButton.tsx | 16 ++ .../EventDestinations/ConfTargetGeneric.tsx | 64 +++---- .../CustomForms/EditConfiguration.tsx | 52 ++--- .../WebhookSettings/AddEndpointModal.tsx | 32 +--- .../WebhookSettings/DeleteWebhookEndpoint.tsx | 12 +- portal-ui/tests/permissions-2/settings.ts | 5 +- portal-ui/tests/utils/elements.ts | 58 +++--- 10 files changed, 189 insertions(+), 404 deletions(-) delete mode 100644 portal-ui/src/screens/Console/Common/VerticalTabs/VerticalTabs.tsx diff --git a/portal-ui/src/screens/Console/Common/VerticalTabs/VerticalTabs.tsx b/portal-ui/src/screens/Console/Common/VerticalTabs/VerticalTabs.tsx deleted file mode 100644 index 776d6a728..000000000 --- a/portal-ui/src/screens/Console/Common/VerticalTabs/VerticalTabs.tsx +++ /dev/null @@ -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 ( - - - - - {headerList.map((item, index) => { - if (item) { - return ( - - ); - } - return null; - })} - - - - - {!isRouteTabs - ? contentList.map((item, index) => { - return ( - - {item ? item : null} - - ); - }) - : null} - {isRouteTabs ? ( -
{routes}
- ) : null} -
-
-
- ); -}; - -export default withStyles(styles)(VerticalTabs); diff --git a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ConfigurationOptions.tsx b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ConfigurationOptions.tsx index 57dde72d2..1b798ba39 100644 --- a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ConfigurationOptions.tsx +++ b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ConfigurationOptions.tsx @@ -15,27 +15,31 @@ // along with this program. If not, see . import React, { Fragment, useCallback, 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 { + Box, + Grid, + HelpBox, + PageLayout, + ScreenTitle, + SettingsIcon, + Tabs, +} from "mds"; import { configurationElements } from "../utils"; import { - actionsTray, - containerForHeader, - searchField, -} from "../../Common/FormComponents/common/styleLibrary"; -import { HelpBox, PageLayout, SettingsIcon } from "mds"; -import { Link, Navigate, Route, Routes, useLocation } from "react-router-dom"; -import VerticalTabs from "../../Common/VerticalTabs/VerticalTabs"; -import ScreenTitle from "../../Common/ScreenTitle/ScreenTitle"; + Navigate, + Route, + Routes, + useLocation, + useNavigate, +} from "react-router-dom"; + import ConfigurationForm from "./ConfigurationForm"; import { IAM_PAGES } from "../../../../common/SecureComponent/permissions"; import PageHeaderWrapper from "../../Common/PageHeaderWrapper/PageHeaderWrapper"; import ExportConfigButton from "./ExportConfigButton"; import ImportConfigButton from "./ImportConfigButton"; -import { Box } from "@mui/material"; + import HelpMenu from "../../HelpMenu"; import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice"; import { useAppDispatch } from "../../../../store"; @@ -43,26 +47,6 @@ import { api } from "../../../../api"; import { IElement } from "../types"; 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) => { return `${IAM_PAGES.SETTINGS}/${path}`; }; @@ -71,9 +55,10 @@ const getRoutePath = (path: string) => { const NON_SUB_SYS_CONFIG_ITEMS = ["region"]; const IGNORED_CONFIG_SUB_SYS = ["cache"]; // cache config is not supported. -const ConfigurationOptions = ({ classes }: IConfigurationOptions) => { +const ConfigurationOptions = () => { const { pathname = "" } = useLocation(); const dispatch = useAppDispatch(); + const navigate = useNavigate(); const [configSubSysList, setConfigSubSysList] = useState([]); const fetchConfigSubSysList = useCallback(async () => { @@ -99,8 +84,6 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => { }); }, [dispatch]); - let selConfigTab = pathname.substring(pathname.lastIndexOf("/") + 1); - selConfigTab = selConfigTab === "settings" ? "region" : selConfigTab; useEffect(() => { fetchConfigSubSysList(); dispatch(setHelpName("settings_Region")); @@ -121,59 +104,57 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => { } /> - -
- } - title={"MinIO Configuration:"} - actions={ - - - - - } - /> - - {availableConfigSubSys.map((element) => ( - } - /> - ))} + + } + title={"MinIO Configuration:"} + actions={ + + + + + } + sx={{ marginBottom: 15 }} + /> + { + navigate(path); + }} + useRouteTabs + options={availableConfigSubSys.map((element) => { + const { configuration_id, configuration_label, icon } = element; + return { + tabConfig: { + id: `settings-tab-${configuration_label}`, + label: configuration_label, + value: configuration_id, + icon: icon, + to: getRoutePath(configuration_id), + }, + }; + })} + routes={ + + {availableConfigSubSys.map((element) => ( } + key={`configItem-${element.configuration_label}`} + path={`${element.configuration_id}`} + element={} /> - - } - > - {availableConfigSubSys.map((element) => { - const { configuration_id, configuration_label, icon } = element; - return { - tabConfig: { - label: configuration_label, - value: configuration_id, - icon: icon, - component: Link, - to: getRoutePath(configuration_id), - }, - }; - })} - -
+ ))} + } + /> + + } + />
{ ); }; -export default withStyles(styles)(ConfigurationOptions); +export default ConfigurationOptions; diff --git a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ExportConfigButton.tsx b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ExportConfigButton.tsx index 9fe50534a..6b9840764 100644 --- a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ExportConfigButton.tsx +++ b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ExportConfigButton.tsx @@ -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 . + import React from "react"; import { Button, UploadIcon } from "mds"; import useApi from "../../Common/Hooks/useApi"; diff --git a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ImportConfigButton.tsx b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ImportConfigButton.tsx index 63cdeee73..2c84054e5 100644 --- a/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ImportConfigButton.tsx +++ b/portal-ui/src/screens/Console/Configurations/ConfigurationPanels/ImportConfigButton.tsx @@ -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 . + import React, { Fragment, useEffect, useRef, useState } from "react"; import { Button, DownloadIcon } from "mds"; import useApi from "../../Common/Hooks/useApi"; diff --git a/portal-ui/src/screens/Console/EventDestinations/ConfTargetGeneric.tsx b/portal-ui/src/screens/Console/EventDestinations/ConfTargetGeneric.tsx index 0c2e21f3f..5d23d943d 100644 --- a/portal-ui/src/screens/Console/EventDestinations/ConfTargetGeneric.tsx +++ b/portal-ui/src/screens/Console/EventDestinations/ConfTargetGeneric.tsx @@ -14,38 +14,27 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import React, { 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 React, { Fragment, useEffect, useState } from "react"; import { - formFieldStyles, - modalBasic, -} from "../Common/FormComponents/common/styleLibrary"; + CommentBox, + ConsoleIcon, + FormLayout, + Grid, + InputBox, + ReadBox, + Switch, + Tooltip, +} from "mds"; +import { IElementValue, IOverrideEnv, KVField } from "../Configurations/types"; 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 { onChange: (newValue: IElementValue[]) => void; fields: KVField[]; defaultVals?: IElementValue[]; overrideEnv?: IOverrideEnv; - classes: any; } -const styles = (theme: Theme) => - createStyles({ - ...formFieldStyles, - formFieldRow: { - ...formFieldStyles.formFieldRow, - }, - ...modalBasic, - }); - // Function to get defined values, //we make this because the backed sometimes don't return all the keys when there is an initial configuration export const valueDef = ( @@ -71,7 +60,6 @@ const ConfTargetGeneric = ({ fields, defaultVals, overrideEnv, - classes, }: IConfGenericProps) => { const [valueHolder, setValueHolder] = useState([]); const fieldsElements = !fields ? [] : fields; @@ -113,9 +101,8 @@ const ConfTargetGeneric = ({ if (override) { return ( - } - /> + sx={{ width: "100%" }} + > + {override.value} + ); } } @@ -180,15 +170,13 @@ const ConfTargetGeneric = ({ ); case "comment": return ( - ) => - setValueElement(field.name, e.target.value, item) - } + onChange={(e) => setValueElement(field.name, e.target.value, item)} placeholder={field.placeholder} /> ); @@ -210,16 +198,12 @@ const ConfTargetGeneric = ({ }; return ( - - - {fieldsElements.map((field, item) => ( - - {fieldDefinition(field, item)} - - ))} - - + + {fieldsElements.map((field, item) => ( + {fieldDefinition(field, item)} + ))} + ); }; -export default withStyles(styles)(ConfTargetGeneric); +export default ConfTargetGeneric; diff --git a/portal-ui/src/screens/Console/EventDestinations/CustomForms/EditConfiguration.tsx b/portal-ui/src/screens/Console/EventDestinations/CustomForms/EditConfiguration.tsx index d1dae2cd1..4655e66f2 100644 --- a/portal-ui/src/screens/Console/EventDestinations/CustomForms/EditConfiguration.tsx +++ b/portal-ui/src/screens/Console/EventDestinations/CustomForms/EditConfiguration.tsx @@ -15,20 +15,13 @@ // along with this program. If not, see . 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 { Theme } from "@mui/material/styles"; -import createStyles from "@mui/styles/createStyles"; -import withStyles from "@mui/styles/withStyles"; -import { Box } from "@mui/material"; -import Grid from "@mui/material/Grid"; -import ConfTargetGeneric from "../ConfTargetGeneric"; - -import { - fieldBasic, - settingsCommon, -} from "../../Common/FormComponents/common/styleLibrary"; +import { Box, Button, Grid, Loader } from "mds"; +import { useLocation, useNavigate } from "react-router-dom"; +import { useSelector } from "react-redux"; +import { api } from "api"; +import { Configuration, ConfigurationKV } from "api/consoleApi"; +import { errorToHandler } from "api/errors"; import { fieldsConfigurations, overrideFields, @@ -40,7 +33,6 @@ import { IOverrideEnv, KVField, } from "../../Configurations/types"; -import ResetConfigurationModal from "./ResetConfigurationModal"; import { configurationIsLoading, setErrorSnackMessage, @@ -50,31 +42,16 @@ import { } from "../../../../systemSlice"; import { AppState, useAppDispatch } from "../../../../store"; import WebhookSettings from "../WebhookSettings/WebhookSettings"; -import { useSelector } from "react-redux"; -import { api } from "api"; -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", - }, - }); +import ConfTargetGeneric from "../ConfTargetGeneric"; +import ResetConfigurationModal from "./ResetConfigurationModal"; interface IAddNotificationEndpointProps { selectedConfiguration: IConfigurationElement; - classes: any; className?: string; } const EditConfiguration = ({ selectedConfiguration, - classes, className = "", }: IAddNotificationEndpointProps) => { const dispatch = useAppDispatch(); @@ -238,7 +215,15 @@ const EditConfiguration = ({ flexFlow: "column", }} > - +