Modals UI style changes (#331)
Implements new input styles & adjusts information on modal boxes for console. Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 301 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 47 KiB |
@@ -103,6 +103,7 @@ const AddBucket = ({
|
||||
const [bName, setBName] = useState<string>(bucketName);
|
||||
const [addLoading, setAddLoading] = useState<boolean>(false);
|
||||
const [addError, setAddError] = useState<string>("");
|
||||
const [sendEnabled, setSendEnabled] = useState<boolean>(false);
|
||||
|
||||
const addRecord = (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
@@ -141,10 +142,34 @@ const AddBucket = ({
|
||||
const [value] = useDebounce(bName, 1000);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("called");
|
||||
addBucketName(value);
|
||||
}, [value]);
|
||||
|
||||
const resetForm = () => {
|
||||
setBName("");
|
||||
addBucketVersioned(false);
|
||||
addBucketQuota(false);
|
||||
addBucketQuotaType("hard");
|
||||
addBucketQuotaSize("1");
|
||||
addBucketQuotaUnit("TiB");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let valid = false;
|
||||
|
||||
if (bName.trim() !== "") {
|
||||
valid = true;
|
||||
}
|
||||
|
||||
if (enableQuota && valid) {
|
||||
if (quotaSize.trim() === "" || parseInt(quotaSize) === 0) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
setSendEnabled(valid);
|
||||
}, [bName, versioned, quotaType, quotaSize, quotaUnit, enableQuota]);
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
title="Create Bucket"
|
||||
@@ -196,7 +221,8 @@ const AddBucket = ({
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
addBucketVersioned(event.target.checked);
|
||||
}}
|
||||
label={"Turn On Versioning"}
|
||||
label={"Versioning"}
|
||||
indicatorLabel={"On"}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -209,6 +235,7 @@ const AddBucket = ({
|
||||
addBucketQuota(event.target.checked);
|
||||
}}
|
||||
label={"Enable Bucket Quota"}
|
||||
indicatorLabel={"On"}
|
||||
/>
|
||||
</Grid>
|
||||
{enableQuota && (
|
||||
@@ -264,11 +291,19 @@ const AddBucket = ({
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading}
|
||||
disabled={addLoading || !sendEnabled}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
@@ -172,7 +172,7 @@ class ListObjects extends React.Component<
|
||||
xhr.setRequestHeader("Authorization", `Bearer ${token}`);
|
||||
|
||||
xhr.withCredentials = false;
|
||||
xhr.onload = function(event) {
|
||||
xhr.onload = function (event) {
|
||||
// TODO: handle status
|
||||
if (xhr.status == 401 || xhr.status == 403) {
|
||||
listObjects.showSnackBarMessage(
|
||||
@@ -227,7 +227,7 @@ class ListObjects extends React.Component<
|
||||
xhr.setRequestHeader("Authorization", `Bearer ${token}`);
|
||||
xhr.responseType = "blob";
|
||||
|
||||
xhr.onload = function(e) {
|
||||
xhr.onload = function (e) {
|
||||
if (this.status == 200) {
|
||||
var blob = new Blob([this.response], {
|
||||
type: "octet/stream",
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 HelpIcon from "@material-ui/icons/Help";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import { Controlled as CodeMirror } from "react-codemirror2";
|
||||
import { InputLabel, Tooltip } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { fieldBasic } from "../common/styleLibrary";
|
||||
import "./ConsoleCodeMirror.css";
|
||||
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
|
||||
interface ICodeWrapper {
|
||||
value: string;
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
classes: any;
|
||||
onChange?: (editor: any, data: any, value: string) => any;
|
||||
onBeforeChange: (editor: any, data: any, value: string) => any;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...fieldBasic,
|
||||
});
|
||||
|
||||
const CodeMirrorWrapper = ({
|
||||
value,
|
||||
label = "",
|
||||
tooltip = "",
|
||||
classes,
|
||||
onChange = () => {},
|
||||
onBeforeChange,
|
||||
readOnly = false,
|
||||
}: ICodeWrapper) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<InputLabel className={classes.inputLabel}>
|
||||
<span>{label}</span>
|
||||
{tooltip !== "" && (
|
||||
<div className={classes.tooltipContainer}>
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
<HelpIcon className={classes.tooltip} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</InputLabel>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
options={{
|
||||
mode: "javascript",
|
||||
lineNumbers: true,
|
||||
readOnly,
|
||||
}}
|
||||
onBeforeChange={onBeforeChange}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(CodeMirrorWrapper);
|
||||
@@ -0,0 +1,353 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
color: #fff;
|
||||
background: #081C42;
|
||||
direction: ltr;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: rgba(255,255,255,0.8); /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #ffffff80;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
white-space: nowrap;
|
||||
color: #000;
|
||||
font-size: 10px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid white;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0 !important;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
.cm-fat-cursor-mark {
|
||||
background-color: rgba(20, 255, 20, 0.5);
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
}
|
||||
.cm-animate-fat-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
background-color: #7e7;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-rulers {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: -50px; bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
top: 0; bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: #fff;}
|
||||
.cm-s-default .cm-quote {color: #fff;}
|
||||
.cm-negative {color: #fff;}
|
||||
.cm-positive {color: #fff;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #fff;}
|
||||
.cm-s-default .cm-atom {color: #fff;}
|
||||
.cm-s-default .cm-number {color: #fff;}
|
||||
.cm-s-default .cm-def {color: #fff;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #fff;}
|
||||
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #fff;}
|
||||
.cm-s-default .cm-comment {color: #fff;}
|
||||
.cm-s-default .cm-string {color: #fff;}
|
||||
.cm-s-default .cm-string-2 {color: #fff;}
|
||||
.cm-s-default .cm-meta {color: #fff;}
|
||||
.cm-s-default .cm-qualifier {color: #fff;}
|
||||
.cm-s-default .cm-builtin {color: #fff;}
|
||||
.cm-s-default .cm-bracket {color: #fff;}
|
||||
.cm-s-default .cm-tag {color: #fff;}
|
||||
.cm-s-default .cm-attribute {color: #fff;}
|
||||
.cm-s-default .cm-hr {color: #fff;}
|
||||
.cm-s-default .cm-link {color: #fff;}
|
||||
|
||||
.cm-s-default .cm-error {color: #fff;}
|
||||
.cm-invalidchar {color: #fff;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #fff;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #fff;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 50px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -50px; margin-right: -50px;
|
||||
padding-bottom: 50px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 50px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
min-height: 100%;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
|
||||
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-font-variant-ligatures: contextual;
|
||||
font-variant-ligatures: contextual;
|
||||
}
|
||||
.CodeMirror-wrap pre.CodeMirror-line,
|
||||
.CodeMirror-wrap pre.CodeMirror-line-like {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 0.1px; /* Force widget margins to stay inside of the container */
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-rtl pre { direction: rtl; }
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background-color: #ffa;
|
||||
background-color: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
@@ -0,0 +1,156 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 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 {
|
||||
Grid,
|
||||
InputLabel,
|
||||
TextField,
|
||||
TextFieldProps,
|
||||
Tooltip,
|
||||
} from "@material-ui/core";
|
||||
import { OutlinedInputProps } from "@material-ui/core/OutlinedInput";
|
||||
import {
|
||||
createStyles,
|
||||
makeStyles,
|
||||
Theme,
|
||||
withStyles,
|
||||
} from "@material-ui/core/styles";
|
||||
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
|
||||
import HelpIcon from "@material-ui/icons/Help";
|
||||
|
||||
interface CommentBoxProps {
|
||||
label: string;
|
||||
classes: any;
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
value: string | boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
disabled?: boolean;
|
||||
tooltip?: string;
|
||||
index?: number;
|
||||
error?: string;
|
||||
required?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...fieldBasic,
|
||||
...tooltipHelper,
|
||||
inputLabel: {
|
||||
...fieldBasic.inputLabel,
|
||||
marginBottom: 16,
|
||||
fontSize: 14,
|
||||
},
|
||||
textBoxContainer: {
|
||||
flexGrow: 1,
|
||||
position: "relative",
|
||||
},
|
||||
errorState: {
|
||||
color: "#b53b4b",
|
||||
fontSize: 14,
|
||||
position: "absolute",
|
||||
top: 7,
|
||||
right: 7,
|
||||
},
|
||||
cssOutlinedInput: {
|
||||
borderColor: "#9C9C9C",
|
||||
},
|
||||
rootTest: {
|
||||
"& .MuiOutlinedInput-inputMultiline": {
|
||||
...fieldBasic.inputLabel,
|
||||
fontSize: 13,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const CommentBoxWrapper = ({
|
||||
label,
|
||||
onChange,
|
||||
value,
|
||||
id,
|
||||
name,
|
||||
disabled = false,
|
||||
tooltip = "",
|
||||
index = 0,
|
||||
error = "",
|
||||
required = false,
|
||||
placeholder = "",
|
||||
classes,
|
||||
}: CommentBoxProps) => {
|
||||
let inputProps: any = { "data-index": index };
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.fieldContainer} ${
|
||||
error !== "" ? classes.errorInField : ""
|
||||
}`}
|
||||
>
|
||||
{label !== "" && (
|
||||
<InputLabel
|
||||
htmlFor={id}
|
||||
className={`${error !== "" ? classes.fieldLabelError : ""} ${
|
||||
classes.inputLabel
|
||||
}`}
|
||||
>
|
||||
<span>
|
||||
{label}
|
||||
{required ? "*" : ""}
|
||||
</span>
|
||||
{tooltip !== "" && (
|
||||
<div className={classes.tooltipContainer}>
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
<HelpIcon className={classes.tooltip} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</InputLabel>
|
||||
)}
|
||||
|
||||
<div className={classes.textBoxContainer}>
|
||||
<TextField
|
||||
id={id}
|
||||
name={name}
|
||||
fullWidth
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
multiline
|
||||
inputProps={inputProps}
|
||||
error={error !== ""}
|
||||
helperText={error}
|
||||
placeholder={placeholder}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
InputProps={{
|
||||
classes: {
|
||||
notchedOutline: classes.cssOutlinedInput,
|
||||
root: classes.rootTest,
|
||||
},
|
||||
}}
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(CommentBoxWrapper);
|
||||
@@ -22,7 +22,7 @@ import { actionsTray, fieldBasic } from "../common/styleLibrary";
|
||||
import HelpIcon from "@material-ui/icons/Help";
|
||||
|
||||
interface IFormSwitch {
|
||||
label: string;
|
||||
label?: string;
|
||||
classes: any;
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
value: string | boolean;
|
||||
@@ -31,7 +31,9 @@ interface IFormSwitch {
|
||||
disabled?: boolean;
|
||||
tooltip?: string;
|
||||
index?: number;
|
||||
indicatorLabel?: string;
|
||||
checked: boolean;
|
||||
switchOnly?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -82,7 +84,7 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
actionsTitle: {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
color: "#081C42",
|
||||
fontSize: 16,
|
||||
alignSelf: "center",
|
||||
},
|
||||
@@ -95,7 +97,7 @@ const styles = (theme: Theme) =>
|
||||
"& .input": {
|
||||
"&::placeholder": {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
color: "#081C42",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -107,6 +109,15 @@ const styles = (theme: Theme) =>
|
||||
paddingBottom: 14,
|
||||
marginBottom: 20,
|
||||
},
|
||||
indicatorLabel: {
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: "#081C42",
|
||||
margin: "0 8px 0 10px",
|
||||
},
|
||||
switchContainer: {
|
||||
display: "flex",
|
||||
},
|
||||
...actionsTray,
|
||||
...fieldBasic,
|
||||
});
|
||||
@@ -127,7 +138,7 @@ const StyledSwitch = withStyles({
|
||||
color: "#fff",
|
||||
},
|
||||
"&$checked + $track": {
|
||||
backgroundColor: "#000",
|
||||
backgroundColor: "#081C42",
|
||||
opacity: 1,
|
||||
height: 15,
|
||||
},
|
||||
@@ -135,14 +146,14 @@ const StyledSwitch = withStyles({
|
||||
checked: {},
|
||||
track: {
|
||||
height: 15,
|
||||
backgroundColor: "#000",
|
||||
backgroundColor: "#081C42",
|
||||
opacity: 1,
|
||||
padding: 0,
|
||||
marginTop: 1.5,
|
||||
},
|
||||
thumb: {
|
||||
backgroundColor: "#fff",
|
||||
border: "#000 1px solid",
|
||||
border: "#081C42 1px solid",
|
||||
boxShadow: "none",
|
||||
width: 18,
|
||||
height: 18,
|
||||
@@ -152,16 +163,44 @@ const StyledSwitch = withStyles({
|
||||
})(Switch);
|
||||
|
||||
const FormSwitchWrapper = ({
|
||||
label,
|
||||
label = "",
|
||||
onChange,
|
||||
value,
|
||||
id,
|
||||
name,
|
||||
checked = false,
|
||||
disabled = false,
|
||||
switchOnly = false,
|
||||
tooltip = "",
|
||||
indicatorLabel = "",
|
||||
classes,
|
||||
}: IFormSwitch) => {
|
||||
const switchComponent = (
|
||||
<React.Fragment>
|
||||
<div className={classes.switchContainer}>
|
||||
<StyledSwitch
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
color="primary"
|
||||
name={name}
|
||||
inputProps={{ "aria-label": "primary checkbox" }}
|
||||
disabled={disabled}
|
||||
disableRipple
|
||||
disableFocusRipple
|
||||
disableTouchRipple
|
||||
value={value}
|
||||
/>
|
||||
{indicatorLabel !== "" && (
|
||||
<span className={classes.indicatorLabel}>{indicatorLabel}</span>
|
||||
)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
if (switchOnly) {
|
||||
return switchComponent;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={`${classes.wrapperContainer}`}>
|
||||
@@ -177,21 +216,7 @@ const FormSwitchWrapper = ({
|
||||
)}
|
||||
</InputLabel>
|
||||
)}
|
||||
|
||||
<div className={classes.textBoxContainer}>
|
||||
<StyledSwitch
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
color="primary"
|
||||
name={name}
|
||||
inputProps={{ "aria-label": "primary checkbox" }}
|
||||
disabled={disabled}
|
||||
disableRipple
|
||||
disableFocusRipple
|
||||
disableTouchRipple
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
{switchComponent}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -76,11 +76,21 @@ const inputStyles = makeStyles((theme: Theme) =>
|
||||
borderColor: "#9c9c9c",
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
"&.MuiInput-underline::before": {
|
||||
borderColor: "#eaeaea",
|
||||
borderBottomStyle: "solid",
|
||||
},
|
||||
},
|
||||
input: {
|
||||
padding: "15px 5px 10px",
|
||||
color: "#393939",
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
"&:placeholder": {
|
||||
color: "#393939",
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
error: {
|
||||
color: "#b53b4b",
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
withStyles,
|
||||
makeStyles,
|
||||
} from "@material-ui/core/styles";
|
||||
import { fieldBasic, tooltipHelper } from "../common/styleLibrary";
|
||||
import { fieldBasic, radioIcons, tooltipHelper } from "../common/styleLibrary";
|
||||
import HelpIcon from "@material-ui/icons/Help";
|
||||
|
||||
export interface SelectorTypes {
|
||||
@@ -49,8 +49,20 @@ const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...fieldBasic,
|
||||
...tooltipHelper,
|
||||
radioBoxContainer: {
|
||||
flexGrow: 1,
|
||||
radioBoxContainer: {},
|
||||
fieldContainer: {
|
||||
...fieldBasic.fieldContainer,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
borderBottom: "#9c9c9c 1px solid",
|
||||
paddingBottom: 10,
|
||||
marginTop: 11,
|
||||
},
|
||||
checkedOption: {
|
||||
"& .MuiFormControlLabel-label": {
|
||||
color: "#000",
|
||||
fontWeight: 700,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -60,31 +72,7 @@ const radioStyles = makeStyles({
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
borderRadius: "100%",
|
||||
width: 14,
|
||||
height: 14,
|
||||
border: "1px solid #000",
|
||||
},
|
||||
checkedIcon: {
|
||||
borderRadius: "100%",
|
||||
width: 14,
|
||||
height: 14,
|
||||
border: "1px solid #000",
|
||||
padding: 4,
|
||||
position: "relative",
|
||||
"&::after": {
|
||||
content: '" "',
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: "100%",
|
||||
display: "block",
|
||||
position: "absolute",
|
||||
backgroundColor: "#000",
|
||||
top: 2,
|
||||
left: 2,
|
||||
},
|
||||
},
|
||||
...radioIcons,
|
||||
});
|
||||
|
||||
const RadioButton = (props: RadioProps) => {
|
||||
@@ -95,8 +83,8 @@ const RadioButton = (props: RadioProps) => {
|
||||
className={classes.root}
|
||||
disableRipple
|
||||
color="default"
|
||||
checkedIcon={<span className={classes.checkedIcon} />}
|
||||
icon={<span className={classes.icon} />}
|
||||
checkedIcon={<span className={classes.radioSelectedIcon} />}
|
||||
icon={<span className={classes.radioUnselectedIcon} />}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -143,6 +131,11 @@ export const RadioGroupSelector = ({
|
||||
value={selectorOption.value}
|
||||
control={<RadioButton />}
|
||||
label={selectorOption.label}
|
||||
className={
|
||||
selectorOption.value === currentSelection
|
||||
? classes.checkedOption
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -20,7 +20,6 @@ export const fieldBasic = {
|
||||
inputLabel: {
|
||||
fontWeight: 600,
|
||||
marginRight: 10,
|
||||
width: 160,
|
||||
fontSize: 15,
|
||||
color: "#000",
|
||||
textAlign: "left" as const,
|
||||
@@ -53,6 +52,30 @@ export const modalBasic = {
|
||||
formSlider: {
|
||||
marginLeft: 0,
|
||||
},
|
||||
clearButton: {
|
||||
border: "0",
|
||||
backgroundColor: "transparent",
|
||||
color: "#393939",
|
||||
fontWeight: 600,
|
||||
fontSize: 14,
|
||||
marginRight: 10,
|
||||
outline: "0",
|
||||
padding: "16px 25px 16px 25px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
floatingEnabled: {
|
||||
position: "absolute" as const,
|
||||
right: 58,
|
||||
zIndex: 1000,
|
||||
marginTop: -38,
|
||||
},
|
||||
configureString: {
|
||||
border: "#EAEAEA 1px solid",
|
||||
borderRadius: 4,
|
||||
padding: "24px 50px",
|
||||
overflowY: "auto" as const,
|
||||
height: 170,
|
||||
},
|
||||
};
|
||||
|
||||
export const tooltipHelper = {
|
||||
@@ -76,6 +99,21 @@ export const checkboxIcons = {
|
||||
},
|
||||
};
|
||||
|
||||
const radioBasic = {
|
||||
width: 12,
|
||||
height: 12,
|
||||
borderRadius: "100%",
|
||||
};
|
||||
|
||||
export const radioIcons = {
|
||||
radioUnselectedIcon: { ...radioBasic, border: "1px solid #000" },
|
||||
radioSelectedIcon: {
|
||||
...radioBasic,
|
||||
border: "1px solid #000",
|
||||
backgroundColor: "#000",
|
||||
},
|
||||
};
|
||||
|
||||
export const containerForHeader = (bottomSpacing: any) => ({
|
||||
container: {
|
||||
padding: "110px 33px 30px",
|
||||
@@ -137,5 +175,6 @@ export const predefinedList = {
|
||||
color: "#393939",
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
minHeight: 41,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -29,11 +29,12 @@ interface IModalProps {
|
||||
modalOpen: boolean;
|
||||
title: string;
|
||||
children: any;
|
||||
wideLimit?: boolean;
|
||||
}
|
||||
|
||||
const baseCloseLine = {
|
||||
content: '" "',
|
||||
borderLeft: "2px solid #707070",
|
||||
borderLeft: "2px solid #9C9C9C",
|
||||
height: 33,
|
||||
width: 1,
|
||||
position: "absolute",
|
||||
@@ -61,10 +62,10 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
modalCloseIcon: {
|
||||
fontSize: 35,
|
||||
color: "#707070",
|
||||
color: "#9C9C9C",
|
||||
fontWeight: 300,
|
||||
"&:hover": {
|
||||
color: "#000",
|
||||
color: "#9C9C9C",
|
||||
},
|
||||
},
|
||||
closeIcon: {
|
||||
@@ -77,7 +78,7 @@ const styles = (theme: Theme) =>
|
||||
transform: "rotate(-45deg)",
|
||||
},
|
||||
"&:hover::before, &:hover::after": {
|
||||
borderColor: "#000",
|
||||
borderColor: "#9C9C9C",
|
||||
},
|
||||
width: 24,
|
||||
height: 24,
|
||||
@@ -95,6 +96,10 @@ const styles = (theme: Theme) =>
|
||||
modalContent: {
|
||||
padding: "0 50px",
|
||||
},
|
||||
customDialogSize: {
|
||||
width: "100%",
|
||||
maxWidth: 765,
|
||||
},
|
||||
});
|
||||
|
||||
const ModalWrapper = ({
|
||||
@@ -103,15 +108,22 @@ const ModalWrapper = ({
|
||||
title,
|
||||
children,
|
||||
classes,
|
||||
wideLimit = true,
|
||||
}: IModalProps) => {
|
||||
const customSize = wideLimit
|
||||
? {
|
||||
classes: {
|
||||
paper: classes.customDialogSize,
|
||||
},
|
||||
}
|
||||
: { maxWidth: "md" as const, fullWidth: true };
|
||||
return (
|
||||
<Dialog
|
||||
open={modalOpen}
|
||||
onClose={onClose}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
maxWidth={"md"}
|
||||
fullWidth
|
||||
{...customSize}
|
||||
>
|
||||
<div className={classes.dialogContainer}>
|
||||
<div className={classes.closeContainer}>
|
||||
|
||||
@@ -33,7 +33,10 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { TablePaginationActionsProps } from "@material-ui/core/TablePagination/TablePaginationActions";
|
||||
import TableActionButton from "./TableActionButton";
|
||||
import history from "../../../../history";
|
||||
import { checkboxIcons } from "../FormComponents/common/styleLibrary";
|
||||
import {
|
||||
checkboxIcons,
|
||||
radioIcons,
|
||||
} from "../FormComponents/common/styleLibrary";
|
||||
|
||||
//Interfaces for table Items
|
||||
|
||||
@@ -80,6 +83,7 @@ interface TableWrapperProps {
|
||||
entityName: string;
|
||||
selectedItems?: string[];
|
||||
stickyHeader?: boolean;
|
||||
radioSelection?: boolean;
|
||||
paginatorConfig?: IPaginatorConfig;
|
||||
}
|
||||
|
||||
@@ -103,7 +107,8 @@ const styles = (theme: Theme) =>
|
||||
padding: "19px 38px",
|
||||
minHeight: "200px",
|
||||
boxShadow: "none",
|
||||
border: "#e7e7e7 1px solid",
|
||||
border: "#EAEDEE 1px solid",
|
||||
borderRadius: 3,
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
@@ -159,6 +164,7 @@ const styles = (theme: Theme) =>
|
||||
cursor: "pointer",
|
||||
},
|
||||
...checkboxIcons,
|
||||
...radioIcons,
|
||||
});
|
||||
|
||||
// Function that renders Title Columns
|
||||
@@ -239,6 +245,7 @@ const TableWrapper = ({
|
||||
idField,
|
||||
classes,
|
||||
stickyHeader = false,
|
||||
radioSelection = false,
|
||||
paginatorConfig,
|
||||
}: TableWrapperProps) => {
|
||||
const findView = itemActions
|
||||
@@ -333,8 +340,24 @@ const TableWrapper = ({
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
checkedIcon={<span className={classes.checkedIcon} />}
|
||||
icon={<span className={classes.unCheckedIcon} />}
|
||||
checkedIcon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioSelectedIcon
|
||||
: classes.checkedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
icon={
|
||||
<span
|
||||
className={
|
||||
radioSelection
|
||||
? classes.radioUnselectedIcon
|
||||
: classes.unCheckedIcon
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
|
||||
@@ -22,6 +22,8 @@ import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import CSVMultiSelector from "../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
||||
import CommentBoxWrapper from "../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
interface IConfGenericProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -94,20 +96,21 @@ const ConfTargetGeneric = ({
|
||||
const fieldDefinition = (field: KVField, item: number) => {
|
||||
switch (field.type) {
|
||||
case "on|off":
|
||||
const value = valueHolder[item] ? valueHolder[item].value : "false";
|
||||
|
||||
return (
|
||||
<RadioGroupSelector
|
||||
currentSelection={valueHolder[item] ? valueHolder[item].value : ""}
|
||||
<FormSwitchWrapper
|
||||
indicatorLabel="On"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.checked ? "true" : "false";
|
||||
setValueElement(field.name, value, item);
|
||||
}}
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
label={field.label}
|
||||
value={"switch_on"}
|
||||
tooltip={field.tooltip}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setValueElement(field.name, e.target.value, item)
|
||||
}
|
||||
selectorOptions={[
|
||||
{ label: "On", value: "true" },
|
||||
{ label: "Off", value: "false" },
|
||||
]}
|
||||
checked={value === "true"}
|
||||
/>
|
||||
);
|
||||
case "csv":
|
||||
@@ -122,6 +125,20 @@ const ConfTargetGeneric = ({
|
||||
tooltip={field.tooltip}
|
||||
/>
|
||||
);
|
||||
case "comment":
|
||||
return (
|
||||
<CommentBoxWrapper
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
label={field.label}
|
||||
tooltip={field.tooltip}
|
||||
value={valueHolder[item] ? valueHolder[item].value : ""}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setValueElement(field.name, e.target.value, item)
|
||||
}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<InputBoxWrapper
|
||||
@@ -134,6 +151,7 @@ const ConfTargetGeneric = ({
|
||||
setValueElement(field.name, e.target.value, item)
|
||||
}
|
||||
multiline={!!field.multiline}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ import Grid from "@material-ui/core/Grid";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import { IElementValue } from "../types";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
modalBasic,
|
||||
predefinedList,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import CommentBoxWrapper from "../../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
interface IConfMySqlProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -31,6 +36,7 @@ interface IConfMySqlProps {
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalBasic,
|
||||
...predefinedList,
|
||||
});
|
||||
|
||||
const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
@@ -104,44 +110,41 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
setDsnString(cs);
|
||||
}, [user, dbName, password, port, host, setDsnString, configToDsnString]);
|
||||
|
||||
const switcherChangeEvt = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.checked) {
|
||||
// build dsn_string
|
||||
const cs = configToDsnString();
|
||||
setDsnString(cs);
|
||||
} else {
|
||||
// parse dsn_string
|
||||
const kv = parseDsnString(dsnString, [
|
||||
"host",
|
||||
"port",
|
||||
"dbname",
|
||||
"user",
|
||||
"password",
|
||||
]);
|
||||
setHostname(kv.get("host") ? kv.get("host") + "" : "");
|
||||
setPort(kv.get("port") ? kv.get("port") + "" : "");
|
||||
setDbName(kv.get("dbname") ? kv.get("dbname") + "" : "");
|
||||
setUser(kv.get("user") ? kv.get("user") + "" : "");
|
||||
setPassword(kv.get("password") ? kv.get("password") + "" : "");
|
||||
}
|
||||
|
||||
setUseDsnString(event.target.checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container className={classes.formScrollable}>
|
||||
<Grid item xs={12}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={useDsnString}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.checked) {
|
||||
// build dsn_string
|
||||
const cs = configToDsnString();
|
||||
setDsnString(cs);
|
||||
} else {
|
||||
// parse dsn_string
|
||||
const kv = parseDsnString(dsnString, [
|
||||
"host",
|
||||
"port",
|
||||
"dbname",
|
||||
"user",
|
||||
"password",
|
||||
]);
|
||||
setHostname(kv.get("host") ? kv.get("host") + "" : "");
|
||||
setPort(kv.get("port") ? kv.get("port") + "" : "");
|
||||
setDbName(kv.get("dbname") ? kv.get("dbname") + "" : "");
|
||||
setUser(kv.get("user") ? kv.get("user") + "" : "");
|
||||
setPassword(
|
||||
kv.get("password") ? kv.get("password") + "" : ""
|
||||
);
|
||||
}
|
||||
|
||||
setUseDsnString(event.target.checked);
|
||||
}}
|
||||
name="checkedB"
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Enter DSN String"
|
||||
className={classes.formSlider}
|
||||
<FormSwitchWrapper
|
||||
label={"Enter DNS String"}
|
||||
checked={useDsnString}
|
||||
id="checkedB"
|
||||
name="checkedB"
|
||||
onChange={switcherChangeEvt}
|
||||
value={"dnsString"}
|
||||
indicatorLabel={"On"}
|
||||
/>
|
||||
</Grid>
|
||||
{useDsnString ? (
|
||||
@@ -160,62 +163,78 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="host"
|
||||
name="host"
|
||||
label="Host"
|
||||
value={host}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setHostname(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label="DB Name"
|
||||
value={dbName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDbName(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="port"
|
||||
name="port"
|
||||
label="Port"
|
||||
value={port}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPort(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.configureString}>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="host"
|
||||
name="host"
|
||||
label=""
|
||||
placeholder="Enter Host"
|
||||
value={host}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setHostname(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label=""
|
||||
placeholder="Enter DB Name"
|
||||
value={dbName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDbName(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="port"
|
||||
name="port"
|
||||
label=""
|
||||
placeholder="Enter Port"
|
||||
value={port}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPort(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="user"
|
||||
name="user"
|
||||
label="User"
|
||||
value={user}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUser(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="user"
|
||||
name="user"
|
||||
label=""
|
||||
placeholder="Enter User"
|
||||
value={user}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUser(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="password"
|
||||
name="password"
|
||||
label=""
|
||||
placeholder="Enter Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Connection String
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{dsnString}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="password"
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
@@ -224,6 +243,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
id="table"
|
||||
name="table"
|
||||
label="Table"
|
||||
placeholder="Enter Table Name"
|
||||
value={table}
|
||||
tooltip="DB table name to store/update events, table is auto-created"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -252,6 +272,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
id="queue-dir"
|
||||
name="queue_dir"
|
||||
label="Queue Dir"
|
||||
placeholder="Enter Queue Dir"
|
||||
value={queueDir}
|
||||
tooltip="staging dir for undelivered messages e.g. '/home/events'"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -264,6 +285,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
id="queue-limit"
|
||||
name="queue_limit"
|
||||
label="Queue Limit"
|
||||
placeholder="Enter Queue Limit"
|
||||
type="number"
|
||||
value={queueLimit}
|
||||
tooltip="maximum limit for undelivered messages, defaults to '10000'"
|
||||
@@ -273,11 +295,11 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
<CommentBoxWrapper
|
||||
id="comment"
|
||||
name="comment"
|
||||
label="Comment"
|
||||
multiline={true}
|
||||
placeholder="Enter Comment"
|
||||
value={comment}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setComment(e.target.value);
|
||||
|
||||
@@ -22,7 +22,12 @@ import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBo
|
||||
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import { IElementValue } from "../types";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
modalBasic,
|
||||
predefinedList,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import CommentBoxWrapper from "../../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
interface IConfPostgresProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -32,6 +37,7 @@ interface IConfPostgresProps {
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalBasic,
|
||||
...predefinedList,
|
||||
});
|
||||
|
||||
const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
@@ -45,7 +51,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
const [port, setPort] = useState<string>("");
|
||||
const [user, setUser] = useState<string>("");
|
||||
const [password, setPassword] = useState<string>("");
|
||||
const [sslMode, setSslMode] = useState<string>("require");
|
||||
const [sslMode, setSslMode] = useState<string>(" ");
|
||||
|
||||
const [table, setTable] = useState<string>("");
|
||||
const [format, setFormat] = useState<string>("namespace");
|
||||
@@ -126,8 +132,11 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
if (port !== "") {
|
||||
strValue = `${strValue} port=${port}`;
|
||||
}
|
||||
if (sslMode !== " ") {
|
||||
strValue = `${strValue} sslmode=${sslMode}`;
|
||||
}
|
||||
|
||||
strValue = `${strValue} sslmode=${sslMode}`;
|
||||
strValue = `${strValue} `;
|
||||
|
||||
return strValue.trim();
|
||||
}, [host, dbName, user, password, port, sslMode]);
|
||||
@@ -169,48 +178,44 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
configToString,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (useConnectionString) {
|
||||
// build connection_string
|
||||
const cs = configToString();
|
||||
setConnectionString(cs);
|
||||
|
||||
return;
|
||||
}
|
||||
// parse connection_string
|
||||
const kv = parseConnectionString(connectionString, [
|
||||
"host",
|
||||
"port",
|
||||
"dbname",
|
||||
"user",
|
||||
"password",
|
||||
"sslmode",
|
||||
]);
|
||||
setHostname(kv.get("host") ? kv.get("host") + "" : "");
|
||||
setPort(kv.get("port") ? kv.get("port") + "" : "");
|
||||
setDbName(kv.get("dbname") ? kv.get("dbname") + "" : "");
|
||||
setUser(kv.get("user") ? kv.get("user") + "" : "");
|
||||
setPassword(kv.get("password") ? kv.get("password") + "" : "");
|
||||
setSslMode(kv.get("sslmode") ? kv.get("sslmode") + "" : " ");
|
||||
}, [useConnectionString]);
|
||||
|
||||
return (
|
||||
<Grid container className={classes.formScrollable}>
|
||||
<Grid item xs={12}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={useConnectionString}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.checked) {
|
||||
// build connection_string
|
||||
const cs = configToString();
|
||||
setConnectionString(cs);
|
||||
} else {
|
||||
// parse connection_string
|
||||
const kv = parseConnectionString(connectionString, [
|
||||
"host",
|
||||
"port",
|
||||
"dbname",
|
||||
"user",
|
||||
"password",
|
||||
"sslmode",
|
||||
]);
|
||||
setHostname(kv.get("host") ? kv.get("host") + "" : "");
|
||||
setPort(kv.get("port") ? kv.get("port") + "" : "");
|
||||
setDbName(kv.get("dbname") ? kv.get("dbname") + "" : "");
|
||||
setUser(kv.get("user") ? kv.get("user") + "" : "");
|
||||
setPassword(
|
||||
kv.get("password") ? kv.get("password") + "" : ""
|
||||
);
|
||||
setSslMode(
|
||||
kv.get("sslmode") ? kv.get("sslmode") + "" : "require"
|
||||
);
|
||||
}
|
||||
|
||||
setUseConnectionString(event.target.checked);
|
||||
}}
|
||||
name="checkedB"
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Enter Connection String"
|
||||
className={classes.formSlider}
|
||||
<FormSwitchWrapper
|
||||
label={"Manually Configure String"}
|
||||
checked={useConnectionString}
|
||||
id="manualString"
|
||||
name="manualString"
|
||||
onChange={(e) => {
|
||||
setUseConnectionString(e.target.checked);
|
||||
}}
|
||||
value={"manualString"}
|
||||
indicatorLabel={"On"}
|
||||
/>
|
||||
</Grid>
|
||||
{useConnectionString ? (
|
||||
@@ -229,81 +234,97 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="host"
|
||||
name="host"
|
||||
label="Host"
|
||||
value={host}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setHostname(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<Grid item xs={12} className={classes.configureString}>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="host"
|
||||
name="host"
|
||||
label=""
|
||||
placeholder="Enter Host"
|
||||
value={host}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setHostname(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label=""
|
||||
placeholder="Enter DB Name"
|
||||
value={dbName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDbName(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="port"
|
||||
name="port"
|
||||
label=""
|
||||
placeholder="Enter Port"
|
||||
value={port}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPort(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SelectWrapper
|
||||
value={sslMode}
|
||||
label=""
|
||||
id="sslmode"
|
||||
name="sslmode"
|
||||
onChange={(e): void => {
|
||||
if (e.target.value !== undefined) {
|
||||
setSslMode(e.target.value + "");
|
||||
}
|
||||
}}
|
||||
options={[
|
||||
{ label: "Enter SSL Mode", value: " " },
|
||||
{ label: "Require", value: "require" },
|
||||
{ label: "Disable", value: "disable" },
|
||||
{ label: "Verify CA", value: "verify-ca" },
|
||||
{ label: "Verify Full", value: "verify-full" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="user"
|
||||
name="user"
|
||||
label=""
|
||||
placeholder="Enter User"
|
||||
value={user}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUser(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="password"
|
||||
name="password"
|
||||
label=""
|
||||
type="password"
|
||||
placeholder="Enter Password"
|
||||
value={password}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Connection String
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{connectionString}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label="DB Name"
|
||||
value={dbName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDbName(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="port"
|
||||
name="port"
|
||||
label="Port"
|
||||
value={port}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPort(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<SelectWrapper
|
||||
value={sslMode}
|
||||
label="SSL Mode"
|
||||
id="sslmode"
|
||||
name="sslmode"
|
||||
onChange={(e): void => {
|
||||
if (e.target.value !== undefined) {
|
||||
setSslMode(e.target.value + "");
|
||||
}
|
||||
}}
|
||||
options={[
|
||||
{ label: "Require", value: "require" },
|
||||
{ label: "Disable", value: "disable" },
|
||||
{ label: "Verify CA", value: "verify-ca" },
|
||||
{ label: "Verify Full", value: "verify-full" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="user"
|
||||
name="user"
|
||||
label="User"
|
||||
value={user}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUser(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="password"
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
@@ -312,6 +333,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
id="table"
|
||||
name="table"
|
||||
label="Table"
|
||||
placeholder={"Enter Table Name"}
|
||||
value={table}
|
||||
tooltip="DB table name to store/update events, table is auto-created"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -340,6 +362,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
id="queue-dir"
|
||||
name="queue_dir"
|
||||
label="Queue Dir"
|
||||
placeholder="Enter Queue Directory"
|
||||
value={queueDir}
|
||||
tooltip="staging dir for undelivered messages e.g. '/home/events'"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -352,6 +375,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
id="queue-limit"
|
||||
name="queue_limit"
|
||||
label="Queue Limit"
|
||||
placeholder="Enter Queue Limit"
|
||||
type="number"
|
||||
value={queueLimit}
|
||||
tooltip="maximum limit for undelivered messages, defaults to '10000'"
|
||||
@@ -361,11 +385,11 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
<CommentBoxWrapper
|
||||
id="comment"
|
||||
name="comment"
|
||||
label="Comment"
|
||||
multiline={true}
|
||||
placeholder="Enter Comment"
|
||||
value={comment}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setComment(e.target.value);
|
||||
|
||||
@@ -27,7 +27,9 @@ export type KVFieldType =
|
||||
| "duration"
|
||||
| "uri"
|
||||
| "sentence"
|
||||
| "csv";
|
||||
| "csv"
|
||||
| "comment"
|
||||
| "switch";
|
||||
|
||||
export interface KVField {
|
||||
name: string;
|
||||
@@ -37,6 +39,7 @@ export interface KVField {
|
||||
type: KVFieldType;
|
||||
options?: SelectorTypes[];
|
||||
multiline?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export interface IConfigurationElement {
|
||||
|
||||
@@ -71,7 +71,7 @@ export const fieldsConfigurations: any = {
|
||||
required: false,
|
||||
label: "comment",
|
||||
tooltip: "You can add a comment to this setting",
|
||||
type: "string",
|
||||
type: "comment",
|
||||
multiline: true,
|
||||
},
|
||||
],
|
||||
@@ -132,7 +132,7 @@ export const fieldsConfigurations: any = {
|
||||
required: false,
|
||||
label: "Comment",
|
||||
tooltip: "You can add a comment to this setting",
|
||||
type: "string",
|
||||
type: "comment",
|
||||
multiline: true,
|
||||
},
|
||||
],
|
||||
@@ -196,7 +196,7 @@ export const fieldsConfigurations: any = {
|
||||
required: false,
|
||||
label: "Comment",
|
||||
tooltip: "You can add a comment to this setting",
|
||||
type: "string",
|
||||
type: "comment",
|
||||
multiline: true,
|
||||
},
|
||||
],
|
||||
@@ -304,7 +304,7 @@ export const fieldsConfigurations: any = {
|
||||
required: false,
|
||||
label: "Comment",
|
||||
tooltip: "Optionally add a comment to this setting",
|
||||
type: "string",
|
||||
type: "comment",
|
||||
multiline: true,
|
||||
},
|
||||
],
|
||||
@@ -343,11 +343,12 @@ export const fieldsConfigurations: any = {
|
||||
const commonFields = [
|
||||
{
|
||||
name: "queue-dir",
|
||||
label: "Queue Dir",
|
||||
label: "Queue Directory",
|
||||
required: true,
|
||||
|
||||
tooltip: "staging dir for undelivered messages e.g. '/home/events'",
|
||||
type: "string",
|
||||
placeholder: "Enter Queue Directory",
|
||||
},
|
||||
{
|
||||
name: "queue-limit",
|
||||
@@ -356,13 +357,14 @@ const commonFields = [
|
||||
|
||||
tooltip: "maximum limit for undelivered messages, defaults to '10000'",
|
||||
type: "number",
|
||||
placeholder: "Enter Queue Limit",
|
||||
},
|
||||
{
|
||||
name: "comment",
|
||||
label: "Comment",
|
||||
required: false,
|
||||
type: "string",
|
||||
multiline: true,
|
||||
type: "comment",
|
||||
placeholder: "Enter Comment",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -373,46 +375,414 @@ export const notificationEndpointsFields: any = {
|
||||
label: "Brokers",
|
||||
required: true,
|
||||
|
||||
tooltip: "comma separated list of Kafka broker addresses",
|
||||
tooltip: "Comma separated list of Kafka broker addresses",
|
||||
type: "string",
|
||||
placeholder: "Enter Brokers",
|
||||
},
|
||||
{
|
||||
name: "topic",
|
||||
label: "Topic",
|
||||
tooltip: "Kafka topic used for bucket notifications",
|
||||
type: "string",
|
||||
placeholder: "Enter Topic",
|
||||
},
|
||||
{
|
||||
name: "sasl_username",
|
||||
label: "SASL Username",
|
||||
tooltip: "username for SASL/PLAIN or SASL/SCRAM authentication",
|
||||
tooltip: "Username for SASL/PLAIN or SASL/SCRAM authentication",
|
||||
type: "string",
|
||||
placeholder: "Enter SASL Username",
|
||||
},
|
||||
{
|
||||
name: "sasl_password",
|
||||
label: "SASL Password",
|
||||
tooltip: "password for SASL/PLAIN or SASL/SCRAM authentication",
|
||||
tooltip: "Password for SASL/PLAIN or SASL/SCRAM authentication",
|
||||
type: "string",
|
||||
placeholder: "Enter SASL Password",
|
||||
},
|
||||
{
|
||||
name: "sasl_mechanism",
|
||||
label: "SASL Mechanism",
|
||||
tooltip: "sasl authentication mechanism, default 'PLAIN'",
|
||||
tooltip: "SASL authentication mechanism, default 'PLAIN'",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "tls_client_auth",
|
||||
label: "TLS Client Auth",
|
||||
tooltip:
|
||||
"clientAuth determines the Kafka server's policy for TLS client auth",
|
||||
"Client Auth determines the Kafka server's policy for TLS client auth",
|
||||
type: "string",
|
||||
placeholder: "Enter TLS Client Auth",
|
||||
},
|
||||
{
|
||||
name: "sasl",
|
||||
label: "SASL",
|
||||
tooltip: "set to 'on' to enable SASL authentication",
|
||||
tooltip: "Set to 'on' to enable SASL authentication",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "tls",
|
||||
label: "TLS",
|
||||
tooltip: "Set to 'on' to enable TLS",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "tls_skip_verify",
|
||||
label: "TLS skip verify",
|
||||
tooltip:
|
||||
'Trust server TLS without verification, defaults to "on" (verify)',
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "client_tls_cert",
|
||||
label: "client TLS cert",
|
||||
tooltip: "Path to client certificate for mTLS auth",
|
||||
type: "path",
|
||||
placeholder: "Enter TLS Client Cert",
|
||||
},
|
||||
{
|
||||
name: "client_tls_key",
|
||||
label: "client TLS key",
|
||||
tooltip: "Path to client key for mTLS auth",
|
||||
type: "path",
|
||||
placeholder: "Enter TLS Client Key",
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Version",
|
||||
tooltip: "Specify the version of the Kafka cluster e.g '2.2.0'",
|
||||
type: "string",
|
||||
placeholder: "Enter Kafka Version",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyAmqp]: [
|
||||
{
|
||||
name: "url",
|
||||
required: true,
|
||||
label: "URL",
|
||||
tooltip:
|
||||
"AMQP server endpoint e.g. `amqp://myuser:mypassword@localhost:5672`",
|
||||
type: "url",
|
||||
},
|
||||
{
|
||||
name: "exchange",
|
||||
label: "Exchange",
|
||||
tooltip: "Name of the AMQP exchange",
|
||||
type: "string",
|
||||
placeholder: "Enter Exchange",
|
||||
},
|
||||
{
|
||||
name: "exchange_type",
|
||||
label: "Exchange Type",
|
||||
tooltip: "AMQP exchange type",
|
||||
type: "string",
|
||||
placeholder: "Enter Exchange Type",
|
||||
},
|
||||
{
|
||||
name: "routing_key",
|
||||
label: "Routing Key",
|
||||
tooltip: "Routing key for publishing",
|
||||
type: "string",
|
||||
placeholder: "Enter Routing Key",
|
||||
},
|
||||
{
|
||||
name: "mandatory",
|
||||
label: "Mandatory",
|
||||
tooltip:
|
||||
"Quietly ignore undelivered messages when set to 'off', default is 'on'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "durable",
|
||||
label: "Durable",
|
||||
tooltip:
|
||||
"Persist queue across broker restarts when set to 'on', default is 'off'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "no_wait",
|
||||
label: "No Wait",
|
||||
tooltip:
|
||||
"Non-blocking message delivery when set to 'on', default is 'off'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "internal",
|
||||
label: "Internal",
|
||||
tooltip:
|
||||
"Set to 'on' for exchange to be not used directly by publishers, but only when bound to other exchanges",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "auto_deleted",
|
||||
label: "Auto Deleted",
|
||||
tooltip:
|
||||
"Auto delete queue when set to 'on', when there are no consumers",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "delivery_mode",
|
||||
label: "Delivery Mode",
|
||||
tooltip: "Set to '1' for non-persistent or '2' for persistent queue",
|
||||
type: "number",
|
||||
placeholder: "Enter Delivery Mode",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyRedis]: [
|
||||
{
|
||||
name: "address",
|
||||
required: true,
|
||||
label: "Address",
|
||||
tooltip: "Redis server's address. For example: `localhost:6379`",
|
||||
type: "address",
|
||||
placeholder: "Enter Address",
|
||||
},
|
||||
{
|
||||
name: "key",
|
||||
required: true,
|
||||
label: "Key",
|
||||
tooltip: "Redis key to store/update events, key is auto-created",
|
||||
type: "string",
|
||||
placeholder: "Enter Key",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "Password",
|
||||
tooltip: "Redis server password",
|
||||
type: "string",
|
||||
placeholder: "Enter Password",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyMqtt]: [
|
||||
{
|
||||
name: "broker",
|
||||
required: true,
|
||||
label: "Broker",
|
||||
tooltip: "MQTT server endpoint e.g. `tcp://localhost:1883`",
|
||||
type: "uri",
|
||||
placeholder: "Enter Brokers",
|
||||
},
|
||||
{
|
||||
name: "topic",
|
||||
required: true,
|
||||
label: "Topic",
|
||||
tooltip: "name of the MQTT topic to publish",
|
||||
type: "string",
|
||||
placeholder: "Enter Topic",
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "Username",
|
||||
tooltip: "MQTT username",
|
||||
type: "string",
|
||||
placeholder: "Enter Username",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "Password",
|
||||
tooltip: "MQTT password",
|
||||
type: "string",
|
||||
placeholder: "Enter Password",
|
||||
},
|
||||
{
|
||||
name: "qos",
|
||||
label: "QOS",
|
||||
tooltip: "Set the quality of service priority, defaults to '0'",
|
||||
type: "number",
|
||||
placeholder: "Enter QOS",
|
||||
},
|
||||
{
|
||||
name: "keep_alive_interval",
|
||||
label: "Keep Alive Interval",
|
||||
tooltip: "Keep-alive interval for MQTT connections in s,m,h,d",
|
||||
type: "duration",
|
||||
placeholder: "Enter Keep Alive Internal",
|
||||
},
|
||||
{
|
||||
name: "reconnect_interval",
|
||||
label: "Reconnect Interval",
|
||||
tooltip: "Reconnect interval for MQTT connections in s,m,h,d",
|
||||
type: "duration",
|
||||
placeholder: "Enter Reconnect Interval",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyNats]: [
|
||||
{
|
||||
name: "address",
|
||||
required: true,
|
||||
label: "Address",
|
||||
tooltip: "NATS server address e.g. '0.0.0.0:4222'",
|
||||
type: "address",
|
||||
placeholder: "Enter Address",
|
||||
},
|
||||
{
|
||||
name: "subject",
|
||||
required: true,
|
||||
label: "Subject",
|
||||
tooltip: "NATS subscription subject",
|
||||
type: "string",
|
||||
placeholder: "Enter NATS Subject",
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "Username",
|
||||
tooltip: "NATS username",
|
||||
type: "string",
|
||||
placeholder: "Enter NATS Username",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "Password",
|
||||
tooltip: "NATS password",
|
||||
type: "string",
|
||||
placeholder: "Enter NATS password",
|
||||
},
|
||||
{
|
||||
name: "token",
|
||||
label: "Token",
|
||||
tooltip: "NATS token",
|
||||
type: "string",
|
||||
placeholder: "Enter NATS token",
|
||||
},
|
||||
{
|
||||
name: "tls",
|
||||
label: "TLS",
|
||||
tooltip: "Set to 'on' to enable TLS",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "tls_skip_verify",
|
||||
label: "TLS Skip Verify",
|
||||
tooltip:
|
||||
'Trust server TLS without verification, defaults to "on" (verify)',
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "ping_interval",
|
||||
label: "Ping Interval",
|
||||
tooltip: "Client ping commands interval in s,m,h,d. Disabled by default",
|
||||
type: "duration",
|
||||
placeholder: "Enter Ping Interval",
|
||||
},
|
||||
{
|
||||
name: "streaming",
|
||||
label: "Streaming",
|
||||
tooltip: "Set to 'on', to use streaming NATS server",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "streaming_async",
|
||||
label: "Streaming async",
|
||||
tooltip: "Set to 'on', to enable asynchronous publish",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "streaming_max_pub_acks_in_flight",
|
||||
label: "Streaming max publish ACKS in flight",
|
||||
tooltip: "Number of messages to publish without waiting for ACKs",
|
||||
type: "number",
|
||||
placeholder: "Enter Streaming in flight value",
|
||||
},
|
||||
{
|
||||
name: "streaming_cluster_id",
|
||||
label: "Streaming Cluster ID",
|
||||
tooltip: "Unique ID for NATS streaming cluster",
|
||||
type: "string",
|
||||
placeholder: "Enter Streaming Cluster ID",
|
||||
},
|
||||
{
|
||||
name: "cert_authority",
|
||||
label: "Cert Authority",
|
||||
tooltip: "Path to certificate chain of the target NATS server",
|
||||
type: "string",
|
||||
placeholder: "Enter Cert Authority",
|
||||
},
|
||||
{
|
||||
name: "client_cert",
|
||||
label: "Client Cert",
|
||||
tooltip: "Client cert for NATS mTLS auth",
|
||||
type: "string",
|
||||
placeholder: "Enter Client Cert",
|
||||
},
|
||||
{
|
||||
name: "client_key",
|
||||
label: "Client Key",
|
||||
tooltip: "Client cert key for NATS mTLS auth",
|
||||
type: "string",
|
||||
placeholder: "Enter Client Key",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyElasticsearch]: [
|
||||
{
|
||||
name: "url",
|
||||
required: true,
|
||||
label: "URL",
|
||||
tooltip:
|
||||
"Elasticsearch server's address, with optional authentication info",
|
||||
type: "url",
|
||||
placeholder: "Enter URL",
|
||||
},
|
||||
{
|
||||
name: "index",
|
||||
required: true,
|
||||
label: "Index",
|
||||
tooltip:
|
||||
"Elasticsearch index to store/update events, index is auto-created",
|
||||
type: "string",
|
||||
placeholder: "Enter Index",
|
||||
},
|
||||
{
|
||||
name: "format",
|
||||
required: true,
|
||||
label: "Format",
|
||||
tooltip:
|
||||
"'namespace' reflects current bucket/object list and 'access' reflects a journal of object operations, defaults to 'namespace'",
|
||||
type: "enum",
|
||||
placeholder: "Enter Format",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyWebhooks]: [
|
||||
{
|
||||
name: "endpoint",
|
||||
required: true,
|
||||
label: "Endpoint",
|
||||
tooltip:
|
||||
"webhook server endpoint e.g. http://localhost:8080/minio/events",
|
||||
type: "url",
|
||||
placeholder: "Enter Endpoint",
|
||||
},
|
||||
{
|
||||
name: "auth_token",
|
||||
label: "Auth Token",
|
||||
tooltip: "opaque string or JWT authorization token",
|
||||
type: "string",
|
||||
placeholder: "Enter auth_token",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyNsq]: [
|
||||
{
|
||||
name: "nsqd_address",
|
||||
required: true,
|
||||
label: "NSQD Address",
|
||||
tooltip: "NSQ server address e.g. '127.0.0.1:4150'",
|
||||
type: "address",
|
||||
placeholder: "Enter nsqd_address",
|
||||
},
|
||||
{
|
||||
name: "topic",
|
||||
required: true,
|
||||
label: "Topic",
|
||||
tooltip: "NSQ topic",
|
||||
type: "string",
|
||||
placeholder: "Enter Topic",
|
||||
},
|
||||
{
|
||||
name: "tls",
|
||||
label: "TLS",
|
||||
@@ -421,335 +791,7 @@ export const notificationEndpointsFields: any = {
|
||||
},
|
||||
{
|
||||
name: "tls_skip_verify",
|
||||
label: "TLS skip verify",
|
||||
tooltip:
|
||||
'trust server TLS without verification, defaults to "on" (verify)',
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "client_tls_cert",
|
||||
label: "client TLS cert",
|
||||
tooltip: "path to client certificate for mTLS auth",
|
||||
type: "path",
|
||||
},
|
||||
{
|
||||
name: "client_tls_key",
|
||||
label: "client TLS key",
|
||||
tooltip: "path to client key for mTLS auth",
|
||||
type: "path",
|
||||
},
|
||||
{
|
||||
name: "version",
|
||||
label: "Version",
|
||||
tooltip: "specify the version of the Kafka cluster e.g '2.2.0'",
|
||||
type: "string",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyAmqp]: [
|
||||
{
|
||||
name: "url",
|
||||
required: true,
|
||||
label: "url",
|
||||
tooltip:
|
||||
"AMQP server endpoint e.g. `amqp://myuser:mypassword@localhost:5672`",
|
||||
type: "url",
|
||||
},
|
||||
{
|
||||
name: "exchange",
|
||||
label: "exchange",
|
||||
tooltip: "name of the AMQP exchange",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "exchange_type",
|
||||
label: "exchange_type",
|
||||
tooltip: "AMQP exchange type",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "routing_key",
|
||||
label: "routing_key",
|
||||
tooltip: "routing key for publishing",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "mandatory",
|
||||
label: "mandatory",
|
||||
tooltip:
|
||||
"quietly ignore undelivered messages when set to 'off', default is 'on'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "durable",
|
||||
label: "durable",
|
||||
tooltip:
|
||||
"persist queue across broker restarts when set to 'on', default is 'off'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "no_wait",
|
||||
label: "no_wait",
|
||||
tooltip:
|
||||
"non-blocking message delivery when set to 'on', default is 'off'",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "internal",
|
||||
label: "internal",
|
||||
tooltip:
|
||||
"set to 'on' for exchange to be not used directly by publishers, but only when bound to other exchanges",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "auto_deleted",
|
||||
label: "auto_deleted",
|
||||
tooltip:
|
||||
"auto delete queue when set to 'on', when there are no consumers",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "delivery_mode",
|
||||
label: "delivery_mode",
|
||||
tooltip: "set to '1' for non-persistent or '2' for persistent queue",
|
||||
type: "number",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyRedis]: [
|
||||
{
|
||||
name: "address",
|
||||
required: true,
|
||||
label: "address",
|
||||
tooltip: "Redis server's address. For example: `localhost:6379`",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "key",
|
||||
required: true,
|
||||
label: "key",
|
||||
tooltip: "Redis key to store/update events, key is auto-created",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "password",
|
||||
tooltip: "Redis server password",
|
||||
type: "string",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyMqtt]: [
|
||||
{
|
||||
name: "broker",
|
||||
required: true,
|
||||
label: "broker",
|
||||
tooltip: "MQTT server endpoint e.g. `tcp://localhost:1883`",
|
||||
type: "uri",
|
||||
},
|
||||
{
|
||||
name: "topic",
|
||||
required: true,
|
||||
label: "topic",
|
||||
tooltip: "name of the MQTT topic to publish",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "username",
|
||||
tooltip: "MQTT username",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "password",
|
||||
tooltip: "MQTT password",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "qos",
|
||||
label: "qos",
|
||||
tooltip: "set the quality of service priority, defaults to '0'",
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
name: "keep_alive_interval",
|
||||
label: "keep_alive_interval",
|
||||
tooltip: "keep-alive interval for MQTT connections in s,m,h,d",
|
||||
type: "duration",
|
||||
},
|
||||
{
|
||||
name: "reconnect_interval",
|
||||
label: "reconnect_interval",
|
||||
tooltip: "reconnect interval for MQTT connections in s,m,h,d",
|
||||
type: "duration",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyNats]: [
|
||||
{
|
||||
name: "address",
|
||||
required: true,
|
||||
label: "address",
|
||||
tooltip: "NATS server address e.g. '0.0.0.0:4222'",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "subject",
|
||||
required: true,
|
||||
label: "subject",
|
||||
tooltip: "NATS subscription subject",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "username",
|
||||
tooltip: "NATS username",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
label: "password",
|
||||
tooltip: "NATS password",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "token",
|
||||
label: "token",
|
||||
tooltip: "NATS token",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "tls",
|
||||
label: "tls",
|
||||
tooltip: "set to 'on' to enable TLS",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "tls_skip_verify",
|
||||
label: "tls_skip_verify",
|
||||
tooltip:
|
||||
'trust server TLS without verification, defaults to "on" (verify)',
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "ping_interval",
|
||||
label: "ping_interval",
|
||||
tooltip: "client ping commands interval in s,m,h,d. Disabled by default",
|
||||
type: "duration",
|
||||
},
|
||||
{
|
||||
name: "streaming",
|
||||
label: "streaming",
|
||||
tooltip: "set to 'on', to use streaming NATS server",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "streaming_async",
|
||||
label: "streaming_async",
|
||||
tooltip: "set to 'on', to enable asynchronous publish",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "streaming_max_pub_acks_in_flight",
|
||||
label: "streaming_max_pub_acks_in_flight",
|
||||
tooltip: "number of messages to publish without waiting for ACKs",
|
||||
type: "number",
|
||||
},
|
||||
{
|
||||
name: "streaming_cluster_id",
|
||||
label: "streaming_cluster_id",
|
||||
tooltip: "unique ID for NATS streaming cluster",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "cert_authority",
|
||||
label: "cert_authority",
|
||||
tooltip: "path to certificate chain of the target NATS server",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "client_cert",
|
||||
label: "client_cert",
|
||||
tooltip: "client cert for NATS mTLS auth",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "client_key",
|
||||
label: "client_key",
|
||||
tooltip: "client cert key for NATS mTLS auth",
|
||||
type: "string",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyElasticsearch]: [
|
||||
{
|
||||
name: "url",
|
||||
required: true,
|
||||
label: "url",
|
||||
tooltip:
|
||||
"Elasticsearch server's address, with optional authentication info",
|
||||
type: "url",
|
||||
},
|
||||
{
|
||||
name: "index",
|
||||
required: true,
|
||||
label: "index",
|
||||
tooltip:
|
||||
"Elasticsearch index to store/update events, index is auto-created",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "format",
|
||||
required: true,
|
||||
label: "format",
|
||||
tooltip:
|
||||
"'namespace' reflects current bucket/object list and 'access' reflects a journal of object operations, defaults to 'namespace'",
|
||||
type: "enum",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyWebhooks]: [
|
||||
{
|
||||
name: "endpoint",
|
||||
required: true,
|
||||
label: "endpoint",
|
||||
tooltip:
|
||||
"webhook server endpoint e.g. http://localhost:8080/minio/events",
|
||||
type: "url",
|
||||
},
|
||||
{
|
||||
name: "auth_token",
|
||||
label: "auth_token",
|
||||
tooltip: "opaque string or JWT authorization token",
|
||||
type: "string",
|
||||
},
|
||||
...commonFields,
|
||||
],
|
||||
[notifyNsq]: [
|
||||
{
|
||||
name: "nsqd_address",
|
||||
required: true,
|
||||
label: "nsqd_address",
|
||||
tooltip: "NSQ server address e.g. '127.0.0.1:4150'",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
name: "topic",
|
||||
required: true,
|
||||
label: "topic",
|
||||
tooltip: "NSQ topic",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "tls",
|
||||
label: "tls",
|
||||
tooltip: "set to 'on' to enable TLS",
|
||||
type: "on|off",
|
||||
},
|
||||
{
|
||||
name: "tls_skip_verify",
|
||||
label: "tls_skip_verify",
|
||||
label: "TLS Skip Verify",
|
||||
tooltip:
|
||||
'trust server TLS without verification, defaults to "on" (verify)',
|
||||
type: "on|off",
|
||||
|
||||
@@ -19,12 +19,16 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
modalBasic,
|
||||
predefinedList,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import api from "../../../common/api";
|
||||
import UsersSelectors from "./UsersSelectors";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
interface IGroupProps {
|
||||
open: boolean;
|
||||
@@ -54,6 +58,7 @@ const styles = (theme: Theme) =>
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
...predefinedList,
|
||||
});
|
||||
|
||||
const AddGroup = ({
|
||||
@@ -64,11 +69,12 @@ const AddGroup = ({
|
||||
}: IGroupProps) => {
|
||||
//Local States
|
||||
const [groupName, setGroupName] = useState<string>("");
|
||||
const [groupEnabled, setGroupEnabled] = useState<string>("");
|
||||
const [groupEnabled, setGroupEnabled] = useState<boolean>(false);
|
||||
const [saving, isSaving] = useState<boolean>(false);
|
||||
const [addError, setError] = useState<string>("");
|
||||
const [selectedUsers, setSelectedUsers] = useState<string[]>([]);
|
||||
const [loadingGroup, isLoadingGroup] = useState<boolean>(false);
|
||||
const [validGroup, setValidGroup] = useState<boolean>(false);
|
||||
|
||||
//Effects
|
||||
useEffect(() => {
|
||||
@@ -80,6 +86,10 @@ const AddGroup = ({
|
||||
}
|
||||
}, [selectedGroup]);
|
||||
|
||||
useEffect(() => {
|
||||
setValidGroup(groupName.trim() !== "");
|
||||
}, [groupName, selectedUsers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (saving) {
|
||||
const saveRecord = () => {
|
||||
@@ -88,7 +98,7 @@ const AddGroup = ({
|
||||
.invoke("PUT", `/api/v1/groups/${groupName}`, {
|
||||
group: groupName,
|
||||
members: selectedUsers,
|
||||
status: groupEnabled,
|
||||
status: groupEnabled ? "enabled" : "disabled",
|
||||
})
|
||||
.then((res) => {
|
||||
isSaving(false);
|
||||
@@ -133,7 +143,7 @@ const AddGroup = ({
|
||||
api
|
||||
.invoke("GET", `/api/v1/groups/${selectedGroup}`)
|
||||
.then((res: MainGroupProps) => {
|
||||
setGroupEnabled(res.status);
|
||||
setGroupEnabled(res.status === "enabled");
|
||||
setGroupName(res.name);
|
||||
setSelectedUsers(res.members);
|
||||
})
|
||||
@@ -153,12 +163,35 @@ const AddGroup = ({
|
||||
isSaving(true);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
if (selectedGroup === null) {
|
||||
setGroupName("");
|
||||
}
|
||||
|
||||
setSelectedUsers([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
onClose={closeModalAndRefresh}
|
||||
title={selectedGroup !== null ? `Group Edit - ${groupName}` : "Add Group"}
|
||||
title={selectedGroup !== null ? `Edit Group` : "Create Group"}
|
||||
>
|
||||
{selectedGroup !== null && (
|
||||
<div className={classes.floatingEnabled}>
|
||||
<FormSwitchWrapper
|
||||
indicatorLabel={"Enabled"}
|
||||
checked={groupEnabled}
|
||||
value={"group_enabled"}
|
||||
id="group-status"
|
||||
name="group-status"
|
||||
onChange={(e) => {
|
||||
setGroupEnabled(e.target.checked);
|
||||
}}
|
||||
switchOnly
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<form noValidate autoComplete="off" onSubmit={setSaving}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
@@ -174,31 +207,13 @@ const AddGroup = ({
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{selectedGroup !== null ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={groupEnabled}
|
||||
id="group-status"
|
||||
name="group-status"
|
||||
label="Status"
|
||||
onChange={(e) => {
|
||||
setGroupEnabled(e.target.value);
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ label: "Enabled", value: "enabled" },
|
||||
{ label: "Disabled", value: "disabled" },
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
{selectedGroup === null ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="group-name"
|
||||
name="group-name"
|
||||
label="Name"
|
||||
label="Group Name"
|
||||
value={groupName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setGroupName(e.target.value);
|
||||
@@ -206,23 +221,38 @@ const AddGroup = ({
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Group Name
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{selectedGroup}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<UsersSelectors
|
||||
selectedUsers={selectedUsers}
|
||||
setSelectedUsers={setSelectedUsers}
|
||||
editMode={selectedGroup !== null}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={saving}
|
||||
disabled={saving || !validGroup}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
@@ -28,11 +28,16 @@ import TextField from "@material-ui/core/TextField";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import {
|
||||
actionsTray,
|
||||
predefinedList,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
interface IGroupsProps {
|
||||
classes: any;
|
||||
selectedUsers: string[];
|
||||
setSelectedUsers: any;
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -41,10 +46,11 @@ const styles = (theme: Theme) =>
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
paper: {
|
||||
// padding: theme.spacing(2),
|
||||
display: "flex",
|
||||
overflow: "auto",
|
||||
flexDirection: "column",
|
||||
paddingTop: 15,
|
||||
boxShadow: "none",
|
||||
},
|
||||
addSideBar: {
|
||||
width: "320px",
|
||||
@@ -70,36 +76,43 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
},
|
||||
},
|
||||
actionsTray: {
|
||||
textAlign: "left",
|
||||
"& button": {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
filterField: {
|
||||
background: "#FFFFFF",
|
||||
padding: 12,
|
||||
borderRadius: 5,
|
||||
boxShadow: "0px 3px 6px #00000012",
|
||||
width: "100%",
|
||||
zIndex: 500,
|
||||
},
|
||||
noFound: {
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
},
|
||||
tableContainer: {
|
||||
maxHeight: 250,
|
||||
maxHeight: 200,
|
||||
},
|
||||
stickyHeader: {
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
actionsTitle: {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
fontSize: 16,
|
||||
alignSelf: "center",
|
||||
},
|
||||
tableBlock: {
|
||||
marginTop: 15,
|
||||
},
|
||||
filterField: {
|
||||
width: 375,
|
||||
fontWeight: 600,
|
||||
"& .input": {
|
||||
"&::placeholder": {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
},
|
||||
...actionsTray,
|
||||
});
|
||||
|
||||
const UsersSelectors = ({
|
||||
classes,
|
||||
selectedUsers,
|
||||
setSelectedUsers,
|
||||
editMode = false,
|
||||
}: IGroupsProps) => {
|
||||
//Local States
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
@@ -166,21 +179,22 @@ const UsersSelectors = ({
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title>Assign Users</Title>
|
||||
{error !== "" ? <div>{error}</div> : <React.Fragment />}
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.paper}>
|
||||
{loading && <LinearProgress />}
|
||||
{error !== "" ? <div>{error}</div> : <React.Fragment />}
|
||||
{records != null && records.length > 0 ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<span className={classes.actionsTitle}>
|
||||
{editMode ? "Edit" : "Assign"} Members
|
||||
</span>
|
||||
<TextField
|
||||
placeholder="Filter Groups"
|
||||
className={classes.filterField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
@@ -192,7 +206,7 @@ const UsersSelectors = ({
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
columns={[{ label: "Access Key", elementKey: "accessKey" }]}
|
||||
onSelect={selectionChanged}
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
removeEmptyFields,
|
||||
} from "../Configurations/utils";
|
||||
import { IElementValue } from "../Configurations/types";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -60,6 +61,69 @@ const styles = (theme: Theme) =>
|
||||
logoButton: {
|
||||
height: "80px",
|
||||
},
|
||||
lambdaNotif: {
|
||||
border: "#393939 1px solid",
|
||||
borderRadius: 5,
|
||||
width: 101,
|
||||
height: 91,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginBottom: 16,
|
||||
cursor: "pointer",
|
||||
"& img": {
|
||||
maxWidth: 71,
|
||||
maxHeight: 71,
|
||||
},
|
||||
},
|
||||
iconContainer: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
width: 455,
|
||||
justifyContent: "space-between",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
nonIconContainer: {
|
||||
marginBottom: 16,
|
||||
"& button": {
|
||||
marginRight: 16,
|
||||
},
|
||||
},
|
||||
pickTitle: {
|
||||
fontWeight: 600,
|
||||
color: "#393939",
|
||||
fontSize: 14,
|
||||
marginBottom: 16,
|
||||
},
|
||||
lambdaFormIndicator: {
|
||||
display: "flex",
|
||||
marginBottom: 40,
|
||||
},
|
||||
lambdaName: {
|
||||
fontSize: 18,
|
||||
fontWeight: 700,
|
||||
color: "#000",
|
||||
marginBottom: 6,
|
||||
},
|
||||
lambdaSubname: {
|
||||
fontSize: 12,
|
||||
color: "#000",
|
||||
fontWeight: 600,
|
||||
},
|
||||
lambdaIcon: {
|
||||
borderRadius: 5,
|
||||
border: "#393939 1px solid",
|
||||
width: 53,
|
||||
height: 48,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: 16,
|
||||
"& img": {
|
||||
width: 38,
|
||||
},
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
interface IAddNotificationEndpointProps {
|
||||
@@ -136,186 +200,111 @@ const AddNotificationEndpoint = ({
|
||||
}
|
||||
}
|
||||
|
||||
let targetTitle = "";
|
||||
switch (service) {
|
||||
case notifyNsq:
|
||||
targetTitle = "NSQ";
|
||||
break;
|
||||
case notifyWebhooks:
|
||||
targetTitle = "Webhooks";
|
||||
break;
|
||||
case notifyElasticsearch:
|
||||
targetTitle = "Elastic Search";
|
||||
break;
|
||||
case notifyNats:
|
||||
targetTitle = "NATS";
|
||||
break;
|
||||
case notifyMqtt:
|
||||
targetTitle = "MQTT";
|
||||
break;
|
||||
case notifyRedis:
|
||||
targetTitle = "Redis";
|
||||
break;
|
||||
case notifyKafka:
|
||||
targetTitle = "Kafka";
|
||||
break;
|
||||
case notifyPostgres:
|
||||
targetTitle = "Postgres";
|
||||
break;
|
||||
case notifyMysql:
|
||||
targetTitle = "Mysql";
|
||||
break;
|
||||
case notifyAmqp:
|
||||
targetTitle = "AMQP";
|
||||
break;
|
||||
}
|
||||
const servicesList = [
|
||||
{
|
||||
actionTrigger: notifyPostgres,
|
||||
targetTitle: "Postgres SQL",
|
||||
logo: "/postgres.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyKafka,
|
||||
targetTitle: "Kafka",
|
||||
logo: "/kafka.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyAmqp,
|
||||
targetTitle: "AMQP",
|
||||
logo: "/amqp.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyMqtt,
|
||||
targetTitle: "MQTT",
|
||||
logo: "/mqtt.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyRedis,
|
||||
targetTitle: "Redis",
|
||||
logo: "/redis.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyNats,
|
||||
targetTitle: "NATS",
|
||||
logo: "/nats.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyMysql,
|
||||
targetTitle: "Mysql",
|
||||
logo: "/mysql.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyElasticsearch,
|
||||
targetTitle: "Elastic Search",
|
||||
logo: "/elasticsearch.png",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyWebhooks,
|
||||
targetTitle: "Webhook",
|
||||
logo: "",
|
||||
},
|
||||
{
|
||||
actionTrigger: notifyNsq,
|
||||
targetTitle: "NSQ",
|
||||
logo: "",
|
||||
},
|
||||
];
|
||||
|
||||
const nonLogos = servicesList.filter((elService) => elService.logo === "");
|
||||
const withLogos = servicesList.filter((elService) => elService.logo !== "");
|
||||
|
||||
const targetElement = servicesList.find(
|
||||
(element) => element.actionTrigger === service
|
||||
);
|
||||
|
||||
const goBack = () => {
|
||||
setService("");
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
onClose={closeModalAndRefresh}
|
||||
title={`Add Lambda Notification Target ${targetTitle}`}
|
||||
>
|
||||
<ModalWrapper modalOpen={open} onClose={closeModalAndRefresh} title={""}>
|
||||
{service === "" && (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<p>Pick a supported service:</p>
|
||||
<table className={classes.chooseTable} style={{ width: "100%" }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyPostgres);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/postgres.png"
|
||||
className={classes.logoButton}
|
||||
alt="postgres"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyKafka);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/kafka.png"
|
||||
className={classes.logoButton}
|
||||
alt="kafka"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyAmqp);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/amqp.png"
|
||||
className={classes.logoButton}
|
||||
alt="amqp"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyMqtt);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/mqtt.png"
|
||||
className={classes.logoButton}
|
||||
alt="mqtt"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyRedis);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/redis.png"
|
||||
className={classes.logoButton}
|
||||
alt="redis"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyNats);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/nats.png"
|
||||
className={classes.logoButton}
|
||||
alt="nats"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyMysql);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/mysql.png"
|
||||
className={classes.logoButton}
|
||||
alt="mysql"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyElasticsearch);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/elasticsearch.png"
|
||||
className={classes.logoButton}
|
||||
alt="elasticsearch"
|
||||
/>
|
||||
</Button>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyWebhooks);
|
||||
}}
|
||||
>
|
||||
Webhook
|
||||
</Button>
|
||||
</td>
|
||||
<td>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setService(notifyNsq);
|
||||
}}
|
||||
>
|
||||
NSQ
|
||||
</Button>
|
||||
</td>
|
||||
<td />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div className={classes.pickTitle}>Pick a supported service:</div>
|
||||
<div className={classes.nonIconContainer}>
|
||||
{nonLogos.map((item) => {
|
||||
return (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
key={`non-icon-${item.targetTitle}`}
|
||||
onClick={() => {
|
||||
setService(item.actionTrigger);
|
||||
}}
|
||||
>
|
||||
{item.targetTitle.toUpperCase()}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className={classes.iconContainer}>
|
||||
{withLogos.map((item) => {
|
||||
return (
|
||||
<a
|
||||
key={`icon-${item.targetTitle}`}
|
||||
className={classes.lambdaNotif}
|
||||
onClick={() => {
|
||||
setService(item.actionTrigger);
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={item.logo}
|
||||
className={classes.logoButton}
|
||||
alt={item.targetTitle}
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
@@ -342,10 +331,37 @@ const AddNotificationEndpoint = ({
|
||||
</Grid>
|
||||
)}
|
||||
<form noValidate onSubmit={submitForm}>
|
||||
<Grid item xs={12} className={classes.lambdaFormIndicator}>
|
||||
{targetElement && targetElement.logo !== "" && (
|
||||
<div className={classes.lambdaIcon}>
|
||||
<img
|
||||
src={targetElement.logo}
|
||||
alt={targetElement.targetTitle}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={classes.lambdaTitle}>
|
||||
<div className={classes.lambdaName}>
|
||||
{targetElement ? targetElement.targetTitle : ""}
|
||||
</div>
|
||||
<div className={classes.lambdaSubname}>
|
||||
Add Lambda Notification Target
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{srvComponent}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={goBack}
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
|
||||
@@ -16,19 +16,18 @@
|
||||
|
||||
import React from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import { UnControlled as CodeMirror } from "react-codemirror2";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import api from "../../../common/api";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import "codemirror/theme/material.css";
|
||||
import { Policy } from "./types";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
fieldBasic,
|
||||
modalBasic,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -39,26 +38,11 @@ const styles = (theme: Theme) =>
|
||||
minHeight: 400,
|
||||
width: "100%",
|
||||
},
|
||||
codeMirror: {
|
||||
fontSize: 14,
|
||||
"& .CodeMirror": {
|
||||
color: "#fff",
|
||||
backgroundColor: "#081C42",
|
||||
},
|
||||
"& .CodeMirror-gutter": {
|
||||
backgroundColor: "#081C4280",
|
||||
},
|
||||
"& .CodeMirror-linenumber": {
|
||||
color: "#000",
|
||||
fontSize: 10,
|
||||
height: 20,
|
||||
lineHeight: "20px",
|
||||
},
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
...fieldBasic,
|
||||
});
|
||||
|
||||
interface IAddPolicyProps {
|
||||
@@ -121,13 +105,26 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
|
||||
if (policyEdit) {
|
||||
this.setState({
|
||||
policyName: policyEdit.name,
|
||||
policyDefinition: policyEdit
|
||||
? JSON.stringify(JSON.parse(policyEdit.policy), null, 4)
|
||||
: "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resetForm() {
|
||||
this.setState({
|
||||
policyName: "",
|
||||
policyDefinition: "",
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, open, policyEdit } = this.props;
|
||||
const { addLoading, addError, policyName } = this.state;
|
||||
const { addLoading, addError, policyName, policyDefinition } = this.state;
|
||||
|
||||
const validSave = policyName.trim() !== "";
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
@@ -163,6 +160,7 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
|
||||
id="policy-name"
|
||||
name="policy-name"
|
||||
label="Policy Name"
|
||||
placeholder="Enter Policy Name"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ policyName: e.target.value });
|
||||
}}
|
||||
@@ -173,31 +171,32 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<CodeMirror
|
||||
className={classes.codeMirror}
|
||||
value={
|
||||
policyEdit
|
||||
? JSON.stringify(JSON.parse(policyEdit.policy), null, 4)
|
||||
: ""
|
||||
}
|
||||
options={{
|
||||
mode: "javascript",
|
||||
lineNumbers: true,
|
||||
}}
|
||||
onChange={(editor, data, value) => {
|
||||
this.setState({ policyDefinition: value });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<CodeMirrorWrapper
|
||||
label="Write Policy"
|
||||
value={policyDefinition}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.setState({ policyDefinition: value });
|
||||
}}
|
||||
readOnly={!!policyEdit}
|
||||
/>
|
||||
</Grid>
|
||||
{!policyEdit && (
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={() => {
|
||||
this.resetForm();
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading}
|
||||
disabled={addLoading || !validSave}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
LinearProgress
|
||||
LinearProgress,
|
||||
} from "@material-ui/core";
|
||||
import api from "../../../common/api";
|
||||
import { PolicyList } from "./types";
|
||||
@@ -32,8 +32,8 @@ import Typography from "@material-ui/core/Typography";
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
errorBlock: {
|
||||
color: "red"
|
||||
}
|
||||
color: "red",
|
||||
},
|
||||
});
|
||||
|
||||
interface IDeletePolicyProps {
|
||||
@@ -54,7 +54,7 @@ class DeletePolicy extends React.Component<
|
||||
> {
|
||||
state: IDeletePolicyState = {
|
||||
deleteLoading: false,
|
||||
deleteError: ""
|
||||
deleteError: "",
|
||||
};
|
||||
removeRecord() {
|
||||
const { deleteLoading } = this.state;
|
||||
@@ -69,17 +69,17 @@ class DeletePolicy extends React.Component<
|
||||
this.setState(
|
||||
{
|
||||
deleteLoading: false,
|
||||
deleteError: ""
|
||||
deleteError: "",
|
||||
},
|
||||
() => {
|
||||
this.props.closeDeleteModalAndRefresh(true);
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
deleteLoading: false,
|
||||
deleteError: err
|
||||
deleteError: err,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,7 +98,7 @@ class DeletePolicy extends React.Component<
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Delete Bucket</DialogTitle>
|
||||
<DialogTitle id="alert-dialog-title">Delete Policy</DialogTitle>
|
||||
<DialogContent>
|
||||
{deleteLoading && <LinearProgress />}
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
|
||||
204
portal-ui/src/screens/Console/Policies/PolicySelectors.tsx
Normal file
@@ -0,0 +1,204 @@
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2020 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, { useEffect, useState } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { LinearProgress } from "@material-ui/core";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import api from "../../../common/api";
|
||||
import { policySort } from "../../../utils/sortFunctions";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import { actionsTray } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { PolicyList } from "./types";
|
||||
|
||||
interface ISelectPolicyProps {
|
||||
classes: any;
|
||||
selectedPolicy?: string;
|
||||
setSelectedPolicy: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
seeMore: {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
paper: {
|
||||
display: "flex",
|
||||
overflow: "auto",
|
||||
flexDirection: "column",
|
||||
paddingTop: 15,
|
||||
boxShadow: "none",
|
||||
},
|
||||
addSideBar: {
|
||||
width: "320px",
|
||||
padding: "20px",
|
||||
},
|
||||
errorBlock: {
|
||||
color: "red",
|
||||
},
|
||||
tableToolbar: {
|
||||
paddingLeft: theme.spacing(2),
|
||||
paddingRight: theme.spacing(0),
|
||||
},
|
||||
wrapCell: {
|
||||
maxWidth: "200px",
|
||||
whiteSpace: "normal",
|
||||
wordWrap: "break-word",
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
"& tr": {
|
||||
"& th": {
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
},
|
||||
noFound: {
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
},
|
||||
tableContainer: {
|
||||
maxHeight: 200,
|
||||
},
|
||||
stickyHeader: {
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
actionsTitle: {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
fontSize: 16,
|
||||
alignSelf: "center",
|
||||
},
|
||||
tableBlock: {
|
||||
marginTop: 15,
|
||||
},
|
||||
filterField: {
|
||||
width: 375,
|
||||
fontWeight: 600,
|
||||
"& .input": {
|
||||
"&::placeholder": {
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
},
|
||||
...actionsTray,
|
||||
});
|
||||
|
||||
const PolicySelectors = ({
|
||||
classes,
|
||||
selectedPolicy = "",
|
||||
setSelectedPolicy,
|
||||
}: ISelectPolicyProps) => {
|
||||
// Local State
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
const [loading, isLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string>("");
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
|
||||
//Effects
|
||||
useEffect(() => {
|
||||
isLoading(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
fetchPolicies();
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
const fetchPolicies = () => {
|
||||
isLoading(true);
|
||||
|
||||
api
|
||||
.invoke("GET", `/api/v1/policies?limit=1000`)
|
||||
.then((res: PolicyList) => {
|
||||
const policies = res.policies === null ? [] : res.policies;
|
||||
isLoading(false);
|
||||
setRecords(policies.sort(policySort));
|
||||
setError("");
|
||||
})
|
||||
.catch((err) => {
|
||||
isLoading(false);
|
||||
setError(err);
|
||||
});
|
||||
};
|
||||
|
||||
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const targetD = e.target;
|
||||
const value = targetD.value;
|
||||
|
||||
setSelectedPolicy(value);
|
||||
};
|
||||
|
||||
const filteredRecords = records.filter((elementItem) =>
|
||||
elementItem.name.includes(filter)
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.paper}>
|
||||
{loading && <LinearProgress />}
|
||||
{error !== "" && <div>{error}</div>}
|
||||
{records != null && records.length > 0 ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<span className={classes.actionsTitle}>Assign Policies</span>
|
||||
<TextField
|
||||
placeholder="Filter by Policy"
|
||||
className={classes.filterField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setFilter(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
columns={[{ label: "Policy", elementKey: "name" }]}
|
||||
onSelect={selectionChanged}
|
||||
selectedItems={[selectedPolicy]}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Policies"
|
||||
idField="name"
|
||||
radioSelection
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<div className={classes.noFound}>No Policies Available</div>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(PolicySelectors);
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import get from "lodash/get";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import {
|
||||
Button,
|
||||
@@ -28,13 +29,17 @@ import {
|
||||
TableRow,
|
||||
} from "@material-ui/core";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
modalBasic,
|
||||
predefinedList,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { User } from "../Users/types";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import { Policy, PolicyList } from "./types";
|
||||
import api from "../../../common/api";
|
||||
import { policySort } from "../../../utils/sortFunctions";
|
||||
import { Group } from "../Groups/types";
|
||||
import PolicySelectors from "./PolicySelectors";
|
||||
|
||||
interface ISetPolicyProps {
|
||||
classes: any;
|
||||
@@ -47,6 +52,7 @@ interface ISetPolicyProps {
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalBasic,
|
||||
...predefinedList,
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
@@ -60,28 +66,12 @@ const SetPolicy = ({
|
||||
open,
|
||||
}: ISetPolicyProps) => {
|
||||
//Local States
|
||||
const [records, setRecords] = useState<Policy[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [actualPolicy, setActualPolicy] = useState<string>("");
|
||||
const [selectedPolicy, setSelectedPolicy] = useState<string>("");
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
const fetchRecords = () => {
|
||||
setLoading(true);
|
||||
|
||||
api
|
||||
.invoke("GET", `/api/v1/policies?limit=1000`)
|
||||
.then((res: PolicyList) => {
|
||||
const policies = res.policies === null ? [] : res.policies;
|
||||
setLoading(false);
|
||||
setRecords(policies.sort(policySort));
|
||||
setError("");
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setError(err);
|
||||
});
|
||||
};
|
||||
|
||||
const setPolicyAction = (policyName: string) => {
|
||||
const setPolicyAction = () => {
|
||||
let entity = "user";
|
||||
let value = null;
|
||||
if (selectedGroup !== null) {
|
||||
@@ -96,7 +86,7 @@ const SetPolicy = ({
|
||||
setLoading(true);
|
||||
|
||||
api
|
||||
.invoke("PUT", `/api/v1/set-policy/${policyName}`, {
|
||||
.invoke("PUT", `/api/v1/set-policy/${selectedPolicy}`, {
|
||||
entityName: value,
|
||||
entityType: entity,
|
||||
})
|
||||
@@ -111,71 +101,89 @@ const SetPolicy = ({
|
||||
});
|
||||
};
|
||||
|
||||
const fetchGroupInformation = () => {
|
||||
if (selectedGroup) {
|
||||
api
|
||||
.invoke("GET", `/api/v1/groups/${selectedGroup}`)
|
||||
.then((res: any) => {
|
||||
const groupPolicy = get(res, "policy", "");
|
||||
setActualPolicy(groupPolicy);
|
||||
setSelectedPolicy(groupPolicy);
|
||||
})
|
||||
.catch((err) => {
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const resetSelection = () => {
|
||||
setSelectedPolicy(actualPolicy);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
fetchRecords();
|
||||
if (selectedGroup !== null) {
|
||||
fetchGroupInformation();
|
||||
return;
|
||||
}
|
||||
|
||||
const userPolicy = get(selectedUser, "policy", "");
|
||||
setActualPolicy(userPolicy);
|
||||
setSelectedPolicy(userPolicy);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
const userName = get(selectedUser, "accessKey", "");
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
onClose={() => {
|
||||
closeModalAndRefresh();
|
||||
}}
|
||||
modalOpen={open}
|
||||
title={
|
||||
selectedUser !== null ? "Set Policy to User" : "Set Policy to Group"
|
||||
}
|
||||
title="Set Policies"
|
||||
>
|
||||
<Grid container className={classes.formScrollable}>
|
||||
<Grid item xs={12}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table
|
||||
className={classes.table}
|
||||
size="small"
|
||||
aria-label="a dense table"
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Policy</TableCell>
|
||||
<TableCell align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{records.map((row) => (
|
||||
<TableRow key={row.name}>
|
||||
<TableCell component="th" scope="row">
|
||||
{row.name}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size={"small"}
|
||||
onClick={() => {
|
||||
setPolicyAction(row.name);
|
||||
}}
|
||||
>
|
||||
Set
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Selected {selectedGroup !== null ? "Group" : "User"}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{selectedGroup !== null ? selectedGroup : userName}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Current Policy
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{actualPolicy}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<PolicySelectors
|
||||
selectedPolicy={selectedPolicy}
|
||||
setSelectedPolicy={setSelectedPolicy}
|
||||
/>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetSelection}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
closeModalAndRefresh();
|
||||
}}
|
||||
disabled={loading}
|
||||
onClick={setPolicyAction}
|
||||
>
|
||||
Cancel
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{loading && (
|
||||
|
||||
@@ -16,19 +16,14 @@
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import { UnControlled as CodeMirror } from "react-codemirror2";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { Button, LinearProgress, Tooltip } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import api from "../../../common/api";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import "codemirror/theme/material.css";
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
import HelpIcon from "@material-ui/icons/Help";
|
||||
|
||||
require("codemirror/mode/javascript/javascript");
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -39,9 +34,6 @@ const styles = (theme: Theme) =>
|
||||
minHeight: 400,
|
||||
width: "100%",
|
||||
},
|
||||
codeMirror: {
|
||||
fontSize: 14,
|
||||
},
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
@@ -92,6 +84,10 @@ const AddServiceAccount = ({
|
||||
setAddSending(true);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setPolicyDefinition("");
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
@@ -120,29 +116,24 @@ const AddServiceAccount = ({
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<Typography component="h5">
|
||||
Optional Policy
|
||||
<Tooltip
|
||||
title="A policy that restricts this service account can be attached."
|
||||
placement="top-start"
|
||||
>
|
||||
<HelpIcon />
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
<CodeMirror
|
||||
className={classes.codeMirror}
|
||||
options={{
|
||||
mode: "javascript",
|
||||
lineNumbers: true,
|
||||
}}
|
||||
onChange={(editor, data, value) => {
|
||||
setPolicyDefinition(value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<CodeMirrorWrapper
|
||||
value={policyDefinition}
|
||||
label="Optional Policy"
|
||||
tooltip="A policy that restricts this service account can be attached."
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setPolicyDefinition(value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
|
||||
@@ -2113,6 +2113,7 @@ const AddTenant = ({
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
wideLimit={false}
|
||||
>
|
||||
{addSending && (
|
||||
<Grid item xs={12}>
|
||||
|
||||
@@ -60,6 +60,7 @@ const AddToGroup = ({
|
||||
}: IAddToGroup) => {
|
||||
//Local States
|
||||
const [saving, isSaving] = useState<boolean>(false);
|
||||
const [accepted, setAccepted] = useState<boolean>(false);
|
||||
const [updatingError, setError] = useState<string>("");
|
||||
const [selectedGroups, setSelectedGroups] = useState<string[]>([]);
|
||||
|
||||
@@ -75,7 +76,7 @@ const AddToGroup = ({
|
||||
.then((res) => {
|
||||
isSaving(false);
|
||||
setError("");
|
||||
closeModalAndRefresh(true);
|
||||
setAccepted(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
isSaving(false);
|
||||
@@ -102,62 +103,100 @@ const AddToGroup = ({
|
||||
isSaving(true);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setSelectedGroups([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
onClose={() => {
|
||||
closeModalAndRefresh(false);
|
||||
closeModalAndRefresh(accepted);
|
||||
}}
|
||||
title="Add Users to Group"
|
||||
title={
|
||||
accepted
|
||||
? "The selected users were added to the following groups."
|
||||
: "Add Users to Group"
|
||||
}
|
||||
>
|
||||
<form noValidate autoComplete="off" onSubmit={setSaving}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
{updatingError !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
component="p"
|
||||
variant="body1"
|
||||
className={classes.errorBlock}
|
||||
>
|
||||
{updatingError}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{accepted ? (
|
||||
<React.Fragment>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Selected Users
|
||||
Groups
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{selectedGroups.join(", ")}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Users
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{checkedUsers.join(", ")}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={setSelectedGroups}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={saving}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{saving && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<form noValidate autoComplete="off" onSubmit={setSaving}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
{updatingError !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
component="p"
|
||||
variant="body1"
|
||||
className={classes.errorBlock}
|
||||
>
|
||||
{updatingError}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Selected Users
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{checkedUsers.join(", ")}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={setSelectedGroups}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetForm}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={saving || selectedGroups.length < 1}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{saving && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
)}
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,13 +19,17 @@ import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { Button, LinearProgress } from "@material-ui/core";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
modalBasic,
|
||||
predefinedList,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { User } from "./types";
|
||||
import api from "../../../common/api";
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -42,6 +46,7 @@ const styles = (theme: Theme) =>
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
...predefinedList,
|
||||
});
|
||||
|
||||
interface IAddUserContentProps {
|
||||
@@ -57,7 +62,8 @@ interface IAddUserContentState {
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
selectedGroups: string[];
|
||||
enabled: string;
|
||||
currentGroups: string[];
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
class AddUserContent extends React.Component<
|
||||
@@ -69,8 +75,9 @@ class AddUserContent extends React.Component<
|
||||
addError: "",
|
||||
accessKey: "",
|
||||
secretKey: "",
|
||||
enabled: "enabled",
|
||||
enabled: false,
|
||||
selectedGroups: [],
|
||||
currentGroups: [],
|
||||
};
|
||||
|
||||
componentDidMount(): void {
|
||||
@@ -103,7 +110,7 @@ class AddUserContent extends React.Component<
|
||||
if (selectedUser !== null) {
|
||||
api
|
||||
.invoke("PUT", `/api/v1/users/${selectedUser.accessKey}`, {
|
||||
status: enabled,
|
||||
status: enabled ? "enabled" : "disabled",
|
||||
groups: selectedGroups,
|
||||
})
|
||||
.then((res) => {
|
||||
@@ -167,7 +174,8 @@ class AddUserContent extends React.Component<
|
||||
addError: "",
|
||||
accessKey: res.accessKey,
|
||||
selectedGroups: res.memberOf || [],
|
||||
enabled: res.status,
|
||||
currentGroups: res.memberOf || [],
|
||||
enabled: res.status === "enabled",
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -178,6 +186,16 @@ class AddUserContent extends React.Component<
|
||||
});
|
||||
}
|
||||
|
||||
resetForm() {
|
||||
if (this.props.selectedUser !== null) {
|
||||
this.setState({ selectedGroups: [] });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ accessKey: "", secretKey: "", selectedGroups: [] });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, selectedUser } = this.props;
|
||||
const {
|
||||
@@ -186,9 +204,15 @@ class AddUserContent extends React.Component<
|
||||
accessKey,
|
||||
secretKey,
|
||||
selectedGroups,
|
||||
currentGroups,
|
||||
enabled,
|
||||
} = this.state;
|
||||
|
||||
const sendEnabled =
|
||||
accessKey.trim() !== "" &&
|
||||
selectedGroups.length > 0 &&
|
||||
((secretKey.trim() !== "" && selectedUser === null) ||
|
||||
selectedUser !== null);
|
||||
return (
|
||||
<ModalWrapper
|
||||
onClose={() => {
|
||||
@@ -197,6 +221,22 @@ class AddUserContent extends React.Component<
|
||||
modalOpen={this.props.open}
|
||||
title={selectedUser !== null ? "Edit User" : "Create User"}
|
||||
>
|
||||
{selectedUser !== null && (
|
||||
<div className={classes.floatingEnabled}>
|
||||
<FormSwitchWrapper
|
||||
indicatorLabel={"Enabled"}
|
||||
checked={enabled}
|
||||
value={"user_enabled"}
|
||||
id="user-status"
|
||||
name="user-status"
|
||||
onChange={(e) => {
|
||||
this.setState({ enabled: e.target.checked });
|
||||
}}
|
||||
switchOnly
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<React.Fragment>
|
||||
<form
|
||||
noValidate
|
||||
@@ -231,19 +271,14 @@ class AddUserContent extends React.Component<
|
||||
/>
|
||||
|
||||
{selectedUser !== null ? (
|
||||
<RadioGroupSelector
|
||||
currentSelection={enabled}
|
||||
id="user-status"
|
||||
name="user-status"
|
||||
label="Status"
|
||||
onChange={(e) => {
|
||||
this.setState({ enabled: e.target.value });
|
||||
}}
|
||||
selectorOptions={[
|
||||
{ label: "Enabled", value: "enabled" },
|
||||
{ label: "Disabled", value: "disabled" },
|
||||
]}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.predefinedTitle}>
|
||||
Current Groups
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.predefinedList}>
|
||||
{currentGroups.join(", ")}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<InputBoxWrapper
|
||||
id="standard-multiline-static"
|
||||
@@ -269,11 +304,21 @@ class AddUserContent extends React.Component<
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<button
|
||||
type="button"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={() => {
|
||||
this.resetForm();
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addLoading}
|
||||
disabled={addLoading || !sendEnabled}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2019 MinIO, Inc.
|
||||
// Copyright (c) 2020 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
|
||||
@@ -283,6 +283,7 @@ class Users extends React.Component<IUsersProps, IUsersState> {
|
||||
selectedGroup={null}
|
||||
closeModalAndRefresh={() => {
|
||||
this.setState({ setPolicyOpen: false });
|
||||
this.fetchRecords();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface User {
|
||||
enabled: boolean;
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
policy?: string;
|
||||
}
|
||||
|
||||
export interface UsersList {
|
||||
|
||||