Restructured settings page to use URL navigation (#1138)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net> Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
// endpoints definition
|
||||
var (
|
||||
configuration = "/settings"
|
||||
configurationItem = "/settings/:option"
|
||||
notificationEndpoints = "/notification-endpoints"
|
||||
notificationEndpointsAddAny = "/notification-endpoints/add/:service"
|
||||
notificationEndpointsAdd = "/notification-endpoints/add"
|
||||
@@ -294,6 +295,7 @@ var displayRules = map[string]func() bool{
|
||||
// endpointRules contains the mapping between endpoints and ActionSets, additional rules can be added here
|
||||
var endpointRules = map[string]ConfigurationActionSet{
|
||||
configuration: configurationActionSet,
|
||||
configurationItem: configurationActionSet,
|
||||
notificationEndpoints: configurationActionSet,
|
||||
notificationEndpointsAdd: configurationActionSet,
|
||||
notificationEndpointsAddAny: configurationActionSet,
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"admin:*",
|
||||
},
|
||||
},
|
||||
want: 29,
|
||||
want: 30,
|
||||
},
|
||||
{
|
||||
name: "all s3 endpoints",
|
||||
@@ -89,7 +89,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 31,
|
||||
want: 32,
|
||||
},
|
||||
{
|
||||
name: "Console User - default endpoints",
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.e33a67ba.chunk.css",
|
||||
"main.js": "./static/js/main.7937d4e3.chunk.js",
|
||||
"main.js.map": "./static/js/main.7937d4e3.chunk.js.map",
|
||||
"main.js": "./static/js/main.368c5d1e.chunk.js",
|
||||
"main.js.map": "./static/js/main.368c5d1e.chunk.js.map",
|
||||
"runtime-main.js": "./static/js/runtime-main.30f8243a.js",
|
||||
"runtime-main.js.map": "./static/js/runtime-main.30f8243a.js.map",
|
||||
"static/css/2.f324abd6.chunk.css": "./static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.332af55f.chunk.js": "./static/js/2.332af55f.chunk.js",
|
||||
"static/js/2.332af55f.chunk.js.map": "./static/js/2.332af55f.chunk.js.map",
|
||||
"static/js/2.97faa37d.chunk.js": "./static/js/2.97faa37d.chunk.js",
|
||||
"static/js/2.97faa37d.chunk.js.map": "./static/js/2.97faa37d.chunk.js.map",
|
||||
"index.html": "./index.html",
|
||||
"static/css/2.f324abd6.chunk.css.map": "./static/css/2.f324abd6.chunk.css.map",
|
||||
"static/css/main.e33a67ba.chunk.css.map": "./static/css/main.e33a67ba.chunk.css.map",
|
||||
"static/js/2.332af55f.chunk.js.LICENSE.txt": "./static/js/2.332af55f.chunk.js.LICENSE.txt"
|
||||
"static/js/2.97faa37d.chunk.js.LICENSE.txt": "./static/js/2.97faa37d.chunk.js.LICENSE.txt"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.30f8243a.js",
|
||||
"static/css/2.f324abd6.chunk.css",
|
||||
"static/js/2.332af55f.chunk.js",
|
||||
"static/js/2.97faa37d.chunk.js",
|
||||
"static/css/main.e33a67ba.chunk.css",
|
||||
"static/js/main.7937d4e3.chunk.js"
|
||||
"static/js/main.368c5d1e.chunk.js"
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: light)"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: dark)"/><meta name="description" content="MinIO Console"/><link href="./styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="./apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="./favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png"/><link rel="manifest" href="./manifest.json"/><link rel="mask-icon" href="./safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="./static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="./static/css/main.e33a67ba.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="./";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="./static/js/2.332af55f.chunk.js"></script><script src="./static/js/main.7937d4e3.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: light)"/><meta name="theme-color" content="#081C42" media="(prefers-color-scheme: dark)"/><meta name="description" content="MinIO Console"/><link href="./styles/root-styles.css" rel="stylesheet"/><link rel="apple-touch-icon" sizes="180x180" href="./apple-icon-180x180.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"/><link rel="icon" type="image/png" sizes="96x96" href="./favicon-96x96.png"/><link rel="icon" type="image/png" sizes="16x16" href="./favicon-16x16.png"/><link rel="manifest" href="./manifest.json"/><link rel="mask-icon" href="./safari-pinned-tab.svg" color="#3a4e54"/><title>MinIO Console</title><link href="./static/css/2.f324abd6.chunk.css" rel="stylesheet"><link href="./static/css/main.e33a67ba.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="loader-block"><svg class="loader-svg-container" viewBox="22 22 44 44"><circle class="loader-style MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></div></div><script>!function(e){function r(r){for(var n,l,i=r[0],a=r[1],p=r[2],c=0,s=[];c<i.length;c++)l=i[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,p||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var a=t[i];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="./";var i=this["webpackJsonpportal-ui"]=this["webpackJsonpportal-ui"]||[],a=i.push.bind(i);i.push=r,i=i.slice();for(var p=0;p<i.length;p++)r(i[p]);var f=a;t()}([])</script><script src="./static/js/2.97faa37d.chunk.js"></script><script src="./static/js/main.368c5d1e.chunk.js"></script></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
portal-ui/build/static/js/2.97faa37d.chunk.js
Normal file
3
portal-ui/build/static/js/2.97faa37d.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
portal-ui/build/static/js/2.97faa37d.chunk.js.map
Normal file
1
portal-ui/build/static/js/2.97faa37d.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,70 @@
|
||||
// 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 { Link } from "react-router-dom";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IElement } from "../../Configurations/types";
|
||||
|
||||
interface ISettingsCard {
|
||||
classes: any;
|
||||
configuration: IElement;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
configurationLink: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 20,
|
||||
width: 190,
|
||||
maxWidth: 190,
|
||||
height: 80,
|
||||
margin: 14,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
color: "#072C4F",
|
||||
fontSize: 14,
|
||||
fontWeight: 700,
|
||||
textDecoration: "none",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
lineClamp: 2,
|
||||
"& svg": {
|
||||
fontSize: 35,
|
||||
marginRight: 15,
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: "#FBFAFA",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const SettingsCard = ({ classes, configuration }: ISettingsCard) => {
|
||||
return (
|
||||
<Link
|
||||
to={`/settings/${configuration.configuration_id}`}
|
||||
className={classes.configurationLink}
|
||||
>
|
||||
{configuration.icon}
|
||||
{configuration.configuration_label}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SettingsCard);
|
||||
@@ -14,46 +14,23 @@
|
||||
// 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 } from "react";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import { Grid } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { containerForHeader } from "../Common/FormComponents/common/styleLibrary";
|
||||
import ConfigurationsList from "./ConfigurationPanels/ConfigurationsList";
|
||||
import { ISessionResponse } from "../types";
|
||||
import React from "react";
|
||||
import { Route, Router, Switch } from "react-router-dom";
|
||||
import history from "../../../history";
|
||||
import ConfigurationOptions from "./ConfigurationPanels/ConfigurationOptions";
|
||||
import ConfigurationForm from "./ConfigurationPanels/ConfigurationForm";
|
||||
import NotFoundPage from "../../NotFoundPage";
|
||||
|
||||
interface IConfigurationMain {
|
||||
classes: any;
|
||||
session: ISessionResponse;
|
||||
distributedSetup: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
headerLabel: {
|
||||
fontSize: 22,
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
marginTop: 4,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const ConfigurationMain = ({ classes }: IConfigurationMain) => {
|
||||
const ConfigurationMain = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label="Settings" />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
<ConfigurationsList />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path="/settings" exact component={ConfigurationOptions} />
|
||||
<Route path="/settings/:option" component={ConfigurationForm} />
|
||||
<Route component={NotFoundPage} />
|
||||
</Switch>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ConfigurationMain);
|
||||
export default ConfigurationMain;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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 } from "react";
|
||||
import get from "lodash/get";
|
||||
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 { configurationElements } from "../utils";
|
||||
import EditConfiguration from "../../NotificationEndpoints/CustomForms/EditConfiguration";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
settingsCommon,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
|
||||
interface IListConfiguration {
|
||||
classes: any;
|
||||
match: any;
|
||||
history: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...searchField,
|
||||
...actionsTray,
|
||||
...settingsCommon,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
strongText: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
keyName: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
iconText: {
|
||||
lineHeight: "24px",
|
||||
},
|
||||
customConfigurationPage: {
|
||||
height: "calc(100vh - 324px)",
|
||||
scrollbarWidth: "none" as const,
|
||||
"&::-webkit-scrollbar": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
mainCont: {
|
||||
...settingsCommon.mainCont,
|
||||
maxWidth: 1180,
|
||||
},
|
||||
});
|
||||
|
||||
const ConfigurationsList = ({
|
||||
classes,
|
||||
match,
|
||||
history,
|
||||
}: IListConfiguration) => {
|
||||
const configurationName = get(match, "params.option", "");
|
||||
|
||||
const findConfiguration = configurationElements.find(
|
||||
(element) => element.configuration_id === configurationName
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader
|
||||
label={`${findConfiguration?.configuration_label} Settings`}
|
||||
/>
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12} className={classes.mainTitle}>
|
||||
<BackLink to="/settings" label="Return to Settings" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{findConfiguration && (
|
||||
<EditConfiguration
|
||||
selectedConfiguration={findConfiguration}
|
||||
history={history}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ConfigurationsList);
|
||||
@@ -0,0 +1,99 @@
|
||||
// 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 } 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 { configurationElements } from "../utils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import SettingsCard from "../../Common/SettingsCard/SettingsCard";
|
||||
|
||||
interface IConfigurationOptions {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
strongText: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
keyName: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
iconText: {
|
||||
lineHeight: "24px",
|
||||
},
|
||||
customConfigurationPage: {
|
||||
height: "calc(100vh - 324px)",
|
||||
scrollbarWidth: "none" as const,
|
||||
"&::-webkit-scrollbar": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
settingsOptionsContainer: {
|
||||
display: "flex" as const,
|
||||
flexDirection: "row" as const,
|
||||
justifyContent: "flex-start" as const,
|
||||
flexWrap: "wrap" as const,
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 5,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
configurationLink: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 20,
|
||||
width: 190,
|
||||
height: 80,
|
||||
margin: 15,
|
||||
},
|
||||
...searchField,
|
||||
...actionsTray,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label={"Settings"} />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.settingsOptionsContainer}>
|
||||
{configurationElements.map((element) => (
|
||||
<SettingsCard
|
||||
configuration={element}
|
||||
key={`configItem-${element.configuration_label}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ConfigurationOptions);
|
||||
@@ -36,6 +36,7 @@ import BackSettingsIcon from "../../../../icons/BackSettingsIcon";
|
||||
|
||||
interface IListConfiguration {
|
||||
classes: any;
|
||||
history: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -67,7 +68,7 @@ const initialConfiguration = {
|
||||
configuration_label: "",
|
||||
};
|
||||
|
||||
const ConfigurationsList = ({ classes }: IListConfiguration) => {
|
||||
const ConfigurationsList = ({ classes, history }: IListConfiguration) => {
|
||||
const [selectedConfiguration, setSelectedConfiguration] =
|
||||
useState(initialConfiguration);
|
||||
const [currentConfiguration, setCurrentConfiguration] = useState<number>(0);
|
||||
@@ -131,9 +132,7 @@ const ConfigurationsList = ({ classes }: IListConfiguration) => {
|
||||
<Grid item xs={12}>
|
||||
{currentConfiguration === 1 ? (
|
||||
<EditConfiguration
|
||||
closeModalAndRefresh={() => {
|
||||
setCurrentConfiguration(0);
|
||||
}}
|
||||
history={history}
|
||||
selectedConfiguration={selectedConfiguration}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
// 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, { useState } from "react";
|
||||
import get from "lodash/get";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import EditConfiguration from "../../NotificationEndpoints/CustomForms/EditConfiguration";
|
||||
import SearchIcon from "../../../../icons/SearchIcon";
|
||||
|
||||
interface IMatchParams {
|
||||
isExact: boolean;
|
||||
params: any;
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface IWebhookPanel {
|
||||
match: IMatchParams;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
interface IWebhook {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
strongText: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
keyName: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
actionsTray: {
|
||||
textAlign: "right",
|
||||
"& button": {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
searchField: {
|
||||
background: "#FFFFFF",
|
||||
padding: 12,
|
||||
borderRadius: 5,
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
},
|
||||
iconText: {
|
||||
lineHeight: "24px",
|
||||
},
|
||||
});
|
||||
|
||||
const panels = {
|
||||
logger: {
|
||||
main: "logger",
|
||||
title: "Logger Webhook Configuration",
|
||||
modalTitle: "Logger Webhook",
|
||||
apiURL: "",
|
||||
configuration: {
|
||||
configuration_id: "logger_webhook",
|
||||
configuration_label: "Logger Webhook",
|
||||
},
|
||||
},
|
||||
audit: {
|
||||
main: "audit",
|
||||
title: "Audit Webhook Configuration",
|
||||
modalTitle: "Audit Webhook",
|
||||
apiURL: "",
|
||||
configuration: {
|
||||
configuration_id: "audit_webhook",
|
||||
configuration_label: "Audit Webhook",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const WebhookPanel = ({ match, classes }: IWebhookPanel) => {
|
||||
const [addWebhookOpen, setAddWebhookOpen] = useState<boolean>(false);
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
// const [webhooks, setWebhooks] = useState<IWebhook[]>([]);
|
||||
|
||||
const pathIn = get(match, "path", "");
|
||||
const panelToDisplay = pathIn.split("/");
|
||||
const panelData = get(panels, panelToDisplay[2], false);
|
||||
|
||||
if (!panelData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const webhooks: IWebhook[] = [];
|
||||
|
||||
const filteredRecords: IWebhook[] = webhooks.filter((elementItem) =>
|
||||
elementItem.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())
|
||||
);
|
||||
|
||||
const tableActions = [
|
||||
{
|
||||
type: "edit",
|
||||
onClick: () => {},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{addWebhookOpen && (
|
||||
<EditConfiguration
|
||||
closeModalAndRefresh={() => {
|
||||
setIsLoading(true);
|
||||
setAddWebhookOpen(false);
|
||||
}}
|
||||
selectedConfiguration={panelData.configuration}
|
||||
/>
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h6">{panelData.title}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Filter"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(event) => {
|
||||
setFilter(event.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddWebhookOpen(true);
|
||||
}}
|
||||
>
|
||||
Add Webhook Configuration
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "name" }]}
|
||||
isLoading={isLoading}
|
||||
records={filteredRecords}
|
||||
entityName="Webhook Configurations"
|
||||
idField="name"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(WebhookPanel);
|
||||
@@ -90,7 +90,7 @@ const TierTypeSelector = ({ classes, history }: ITypeTiersConfig) => {
|
||||
<Grid container className={classes.mainCont}>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.mainTitle}>
|
||||
<BackLink to="/tiers" label="Pick an object store" />
|
||||
<BackLink to="/tiers" label="Return to Configured Tiers" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
|
||||
@@ -53,3 +53,9 @@ export interface IElementValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IElement {
|
||||
configuration_id: string;
|
||||
configuration_label: string;
|
||||
icon?: any;
|
||||
}
|
||||
|
||||
@@ -13,49 +13,75 @@
|
||||
//
|
||||
// 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 { IConfigurationElement, IElementValue } from "./types";
|
||||
import React from "react";
|
||||
import PublicIcon from "@mui/icons-material/Public";
|
||||
import SdStorageIcon from "@mui/icons-material/SdStorage";
|
||||
import CompressIcon from "@mui/icons-material/Compress";
|
||||
import CodeIcon from "@mui/icons-material/Code";
|
||||
import LocalHospitalIcon from "@mui/icons-material/LocalHospital";
|
||||
import FindReplaceIcon from "@mui/icons-material/FindReplace";
|
||||
import VpnKeyIcon from "@mui/icons-material/VpnKey";
|
||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||
import LoginIcon from "@mui/icons-material/Login";
|
||||
import PendingActionsIcon from "@mui/icons-material/PendingActions";
|
||||
import CallToActionIcon from "@mui/icons-material/CallToAction";
|
||||
import { IElement, IElementValue } from "./types";
|
||||
|
||||
export const configurationElements: IConfigurationElement[] = [
|
||||
export const configurationElements: IElement[] = [
|
||||
{
|
||||
icon: <PublicIcon />,
|
||||
configuration_id: "region",
|
||||
configuration_label: "Edit Region Configuration",
|
||||
configuration_label: "Region",
|
||||
},
|
||||
{
|
||||
icon: <SdStorageIcon />,
|
||||
configuration_id: "cache",
|
||||
configuration_label: "Edit Cache Configuration",
|
||||
configuration_label: "Cache",
|
||||
},
|
||||
{
|
||||
icon: <CompressIcon />,
|
||||
configuration_id: "compression",
|
||||
configuration_label: "Edit Compression Configuration",
|
||||
configuration_label: "Compression",
|
||||
},
|
||||
{
|
||||
icon: <CodeIcon />,
|
||||
configuration_id: "api",
|
||||
configuration_label: "Edit API Configuration",
|
||||
configuration_label: "API",
|
||||
},
|
||||
{
|
||||
icon: <LocalHospitalIcon />,
|
||||
configuration_id: "heal",
|
||||
configuration_label: "Edit Heal Configuration",
|
||||
configuration_label: "Heal",
|
||||
},
|
||||
{
|
||||
icon: <FindReplaceIcon />,
|
||||
configuration_id: "scanner",
|
||||
configuration_label: "Edit Scanner Configuration",
|
||||
configuration_label: "Scanner",
|
||||
},
|
||||
{ configuration_id: "etcd", configuration_label: "Edit Etcd Configuration" },
|
||||
{
|
||||
icon: <VpnKeyIcon />,
|
||||
configuration_id: "etcd",
|
||||
configuration_label: "Etcd",
|
||||
},
|
||||
{
|
||||
icon: <LockOpenIcon />,
|
||||
configuration_id: "identity_openid",
|
||||
configuration_label: "Edit Identity Openid Configuration",
|
||||
configuration_label: "Identity Openid",
|
||||
},
|
||||
{
|
||||
icon: <LoginIcon />,
|
||||
configuration_id: "identity_ldap",
|
||||
configuration_label: "Edit Identity LDAP Configuration",
|
||||
configuration_label: "Identity LDAP",
|
||||
},
|
||||
{
|
||||
icon: <CallToActionIcon />,
|
||||
configuration_id: "logger_webhook",
|
||||
configuration_label: "Edit Logger Webhook Configuration",
|
||||
configuration_label: "Logger Webhook",
|
||||
},
|
||||
{
|
||||
icon: <PendingActionsIcon />,
|
||||
configuration_id: "audit_webhook",
|
||||
configuration_label: "Edit Audit Webhook Configuration",
|
||||
configuration_label: "Audit Webhook",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -44,7 +44,6 @@ import Account from "./Account/Account";
|
||||
import Users from "./Users/Users";
|
||||
import Groups from "./Groups/Groups";
|
||||
import ConfigurationMain from "./Configurations/ConfigurationMain";
|
||||
import WebhookPanel from "./Configurations/ConfigurationPanels/WebhookPanel";
|
||||
import TenantsMain from "./Tenants/TenantsMain";
|
||||
import TenantDetails from "./Tenants/TenantDetails/TenantDetails";
|
||||
import License from "./License/License";
|
||||
@@ -286,6 +285,10 @@ const Console = ({
|
||||
component: ConfigurationMain,
|
||||
path: "/settings",
|
||||
},
|
||||
{
|
||||
component: ConfigurationMain,
|
||||
path: "/settings/:option",
|
||||
},
|
||||
{
|
||||
component: AddNotificationEndpoint,
|
||||
path: "/notification-endpoints/add/:service",
|
||||
@@ -317,14 +320,6 @@ const Console = ({
|
||||
changePassword: session.pages.includes("/account/change-password"),
|
||||
},
|
||||
},
|
||||
{
|
||||
component: WebhookPanel,
|
||||
path: "/webhook/logger",
|
||||
},
|
||||
{
|
||||
component: WebhookPanel,
|
||||
path: "/webhook/audit",
|
||||
},
|
||||
{
|
||||
component: TenantsMain,
|
||||
path: "/tenants",
|
||||
|
||||
@@ -63,19 +63,19 @@ const styles = (theme: Theme) =>
|
||||
});
|
||||
|
||||
interface IAddNotificationEndpointProps {
|
||||
closeModalAndRefresh: any;
|
||||
serverNeedsRestart: typeof serverNeedsRestart;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
selectedConfiguration: IConfigurationElement;
|
||||
classes: any;
|
||||
history: any;
|
||||
}
|
||||
|
||||
const EditConfiguration = ({
|
||||
closeModalAndRefresh,
|
||||
serverNeedsRestart,
|
||||
selectedConfiguration,
|
||||
setErrorSnackMessage,
|
||||
classes,
|
||||
history,
|
||||
}: IAddNotificationEndpointProps) => {
|
||||
//Local States
|
||||
const [valuesObj, setValueObj] = useState<IElementValue[]>([]);
|
||||
@@ -116,7 +116,7 @@ const EditConfiguration = ({
|
||||
setSaving(false);
|
||||
serverNeedsRestart(true);
|
||||
|
||||
closeModalAndRefresh();
|
||||
history.push("/settings");
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setSaving(false);
|
||||
@@ -125,10 +125,10 @@ const EditConfiguration = ({
|
||||
}
|
||||
}, [
|
||||
saving,
|
||||
history,
|
||||
serverNeedsRestart,
|
||||
selectedConfiguration,
|
||||
valuesObj,
|
||||
closeModalAndRefresh,
|
||||
setErrorSnackMessage,
|
||||
]);
|
||||
|
||||
@@ -147,39 +147,32 @@ const EditConfiguration = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.customTitle}>
|
||||
{selectedConfiguration.configuration_label}
|
||||
</Grid>
|
||||
<Fragment>
|
||||
<form noValidate onSubmit={submitForm}>
|
||||
<Grid item xs={12} className={classes.settingsFormContainer}>
|
||||
{loadingConfig && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
<ConfTargetGeneric
|
||||
fields={
|
||||
fieldsConfigurations[selectedConfiguration.configuration_id]
|
||||
}
|
||||
onChange={onValueChange}
|
||||
defaultVals={configValues}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.settingsButtonContainer}>
|
||||
<Grid item xs={12} className={classes.innerSettingsButtonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={saving}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<form noValidate onSubmit={submitForm}>
|
||||
<Grid item xs={12} className={classes.settingsFormContainer}>
|
||||
{loadingConfig && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Fragment>
|
||||
)}
|
||||
<ConfTargetGeneric
|
||||
fields={
|
||||
fieldsConfigurations[selectedConfiguration.configuration_id]
|
||||
}
|
||||
onChange={onValueChange}
|
||||
defaultVals={configValues}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.settingsButtonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={saving}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ const NotificationTypeSelector = ({ classes }: INotificationTypeSelector) => {
|
||||
<Grid item xs={12} className={classes.mainTitle}>
|
||||
<BackLink
|
||||
to="/notification-endpoints"
|
||||
label="Pick a supported service"
|
||||
label="Return to Configured Endpoints"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.centerElements}>
|
||||
|
||||
Reference in New Issue
Block a user