Added identifier field to Event destinations page & migrated to mds (#2816)
This commit is contained in:
@@ -14,84 +14,23 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { HelpIconFilled, LambdaNotificationsIcon } from "mds";
|
||||
|
||||
const FeatureItem = ({
|
||||
icon,
|
||||
description,
|
||||
}: {
|
||||
icon: any;
|
||||
description: string;
|
||||
}) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
"& .min-icon": {
|
||||
marginRight: "10px",
|
||||
height: "23px",
|
||||
width: "23px",
|
||||
marginBottom: "10px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{icon}{" "}
|
||||
<div style={{ fontSize: "14px", fontStyle: "italic", color: "#5E5E5E" }}>
|
||||
{description}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
import { HelpBox, LambdaNotificationsIcon, Box } from "mds";
|
||||
|
||||
const NotificationEndpointTypeSelectorHelpBox = () => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
flex: 1,
|
||||
border: "1px solid #eaeaea",
|
||||
borderRadius: "2px",
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
padding: "20px",
|
||||
marginTop: {
|
||||
xs: "0px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginBottom: "16px",
|
||||
paddingBottom: "20px",
|
||||
|
||||
"& .min-icon": {
|
||||
height: "21px",
|
||||
width: "21px",
|
||||
marginRight: "15px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HelpIconFilled />
|
||||
<div>Learn more about Event Destinations</div>
|
||||
</Box>
|
||||
<Box sx={{ fontSize: "14px", marginBottom: "15px" }}>
|
||||
<Box sx={{ paddingBottom: "20px" }}>
|
||||
<FeatureItem
|
||||
icon={<LambdaNotificationsIcon />}
|
||||
description={`What are Event Destinations?`}
|
||||
/>
|
||||
<Box sx={{ paddingTop: "20px" }}>
|
||||
MinIO bucket notifications allow administrators to send
|
||||
notifications to supported external services on certain object or
|
||||
bucket events. MinIO supports bucket and object-level S3 events
|
||||
similar to the Amazon S3 Event Notifications.
|
||||
</Box>
|
||||
<HelpBox
|
||||
iconComponent={<LambdaNotificationsIcon />}
|
||||
title={"What are Event Destinations?"}
|
||||
help={
|
||||
<Box sx={{ paddingTop: "20px" }}>
|
||||
MinIO bucket notifications allow administrators to send notifications
|
||||
to supported external services on certain object or bucket events.
|
||||
MinIO supports bucket and object-level S3 events similar to the Amazon
|
||||
S3 Event Notifications.
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@ export const typesSelection = {
|
||||
height: "80px",
|
||||
},
|
||||
lambdaNotif: {
|
||||
background: "#ffffff",
|
||||
background: "#ffffff50",
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 5,
|
||||
width: 250,
|
||||
|
||||
@@ -17,19 +17,18 @@
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
|
||||
import get from "lodash/get";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { BackLink, Button, PageLayout } from "mds";
|
||||
import { BackLink, Button, FormLayout, Grid, InputBox, PageLayout } from "mds";
|
||||
|
||||
import api from "../../../common/api";
|
||||
import {
|
||||
destinationList,
|
||||
notificationEndpointsFields,
|
||||
notifyMysql,
|
||||
notifyPostgres,
|
||||
removeEmptyFields,
|
||||
destinationList,
|
||||
} from "./utils";
|
||||
import {
|
||||
modalBasic,
|
||||
@@ -49,6 +48,8 @@ import {
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import TargetTitle from "./TargetTitle";
|
||||
import { setDestinationLoading } from "./destinationsSlice";
|
||||
|
||||
const ConfMySql = withSuspense(
|
||||
React.lazy(() => import("./CustomForms/ConfMySql"))
|
||||
@@ -66,43 +67,6 @@ const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalBasic,
|
||||
...settingsCommon,
|
||||
lambdaNotif: {
|
||||
background:
|
||||
"linear-gradient(90deg, rgba(249,249,250,1) 0%, rgba(250,250,251,1) 68%, rgba(254,254,254,1) 100%)",
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 5,
|
||||
height: 80,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "start",
|
||||
marginBottom: 16,
|
||||
cursor: "pointer",
|
||||
padding: 0,
|
||||
overflow: "hidden",
|
||||
},
|
||||
lambdaNotifIcon: {
|
||||
backgroundColor: "#FEFEFE",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 80,
|
||||
height: 80,
|
||||
|
||||
"& img": {
|
||||
maxWidth: 46,
|
||||
maxHeight: 46,
|
||||
},
|
||||
},
|
||||
lambdaNotifTitle: {
|
||||
color: "#07193E",
|
||||
fontSize: 16,
|
||||
fontFamily: "Inter,sans-serif",
|
||||
paddingLeft: 18,
|
||||
},
|
||||
formBox: {
|
||||
border: "1px solid #EAEAEA",
|
||||
padding: 15,
|
||||
},
|
||||
});
|
||||
|
||||
interface IAddNotificationEndpointProps {
|
||||
@@ -120,20 +84,22 @@ const AddEventDestination = ({
|
||||
|
||||
//Local States
|
||||
const [valuesArr, setValueArr] = useState<IElementValue[]>([]);
|
||||
const [identifier, setIdentifier] = useState<string>("");
|
||||
const [saving, setSaving] = useState<boolean>(false);
|
||||
const service = params.service || "";
|
||||
//Effects
|
||||
|
||||
//Effects
|
||||
useEffect(() => {
|
||||
if (saving) {
|
||||
const payload = {
|
||||
key_values: removeEmptyFields(valuesArr),
|
||||
};
|
||||
api
|
||||
.invoke("PUT", `/api/v1/configs/${service}`, payload)
|
||||
.invoke("PUT", `/api/v1/configs/${service}:${identifier}`, payload)
|
||||
.then(() => {
|
||||
setSaving(false);
|
||||
dispatch(setServerNeedsRestart(true));
|
||||
dispatch(setDestinationLoading(true));
|
||||
navigate(IAM_PAGES.EVENT_DESTINATIONS);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
@@ -141,7 +107,15 @@ const AddEventDestination = ({
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
});
|
||||
}
|
||||
}, [saving, service, valuesArr, saveAndRefresh, dispatch, navigate]);
|
||||
}, [
|
||||
saving,
|
||||
service,
|
||||
valuesArr,
|
||||
saveAndRefresh,
|
||||
dispatch,
|
||||
navigate,
|
||||
identifier,
|
||||
]);
|
||||
|
||||
//Fetch Actions
|
||||
const submitForm = (event: React.FormEvent) => {
|
||||
@@ -199,41 +173,54 @@ const AddEventDestination = ({
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
{targetElement && (
|
||||
<div
|
||||
key={`icon-${targetElement.targetTitle}`}
|
||||
className={classes.lambdaNotif}
|
||||
>
|
||||
<div className={classes.lambdaNotifIcon}>
|
||||
<img
|
||||
src={targetElement.logo}
|
||||
className={classes.logoButton}
|
||||
alt={targetElement.targetTitle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={classes.lambdaNotifTitle}>
|
||||
<b>
|
||||
{targetElement ? targetElement.targetTitle : ""} Event
|
||||
Destination
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<TargetTitle
|
||||
logoSrc={targetElement.logo}
|
||||
title={`${
|
||||
targetElement ? targetElement.targetTitle : ""
|
||||
} Event
|
||||
Destination`}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<div className={classes.formBox}>
|
||||
<Grid item xs={12} className={classes.configForm}>
|
||||
<FormLayout>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={classes.formFieldRow}
|
||||
sx={{ marginBottom: "12px" }}
|
||||
>
|
||||
<InputBox
|
||||
id={"identifier-field"}
|
||||
name={"identifier-field"}
|
||||
label={"Identifier"}
|
||||
value={identifier}
|
||||
onChange={(e) => setIdentifier(e.target.value)}
|
||||
tooltip={"Unique descriptive string for this destination"}
|
||||
placeholder="Enter Destination Identifier"
|
||||
required
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{srvComponent}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.settingsButtonContainer}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: 15,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
id={"save-notification-target"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
disabled={saving}
|
||||
disabled={saving || identifier.trim() === ""}
|
||||
label={"Save Event Destination"}
|
||||
/>
|
||||
</Grid>
|
||||
</div>
|
||||
</FormLayout>
|
||||
</Fragment>
|
||||
)}
|
||||
</form>
|
||||
|
||||
@@ -24,12 +24,10 @@ import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import CSVMultiSelector from "../Common/FormComponents/CSVMultiSelector/CSVMultiSelector";
|
||||
import CommentBoxWrapper from "../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import PredefinedList from "../Common/FormComponents/PredefinedList/PredefinedList";
|
||||
import { ConsoleIcon, Tooltip } from "mds";
|
||||
import { ConsoleIcon, InputBox, Switch, Tooltip } from "mds";
|
||||
|
||||
interface IConfGenericProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -144,7 +142,7 @@ const ConfTargetGeneric = ({
|
||||
const value = holderItem ? holderItem.value : "off";
|
||||
|
||||
return (
|
||||
<FormSwitchWrapper
|
||||
<Switch
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.checked ? "on" : "off";
|
||||
setValueElement(field.name, value, item);
|
||||
@@ -195,7 +193,7 @@ const ConfTargetGeneric = ({
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id={field.name}
|
||||
name={field.name}
|
||||
label={field.label}
|
||||
@@ -204,7 +202,6 @@ const ConfTargetGeneric = ({
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setValueElement(field.name, e.target.value, item)
|
||||
}
|
||||
multiline={!!field.multiline}
|
||||
placeholder={field.placeholder}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2022 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
|
||||
import { ConfirmModalIcon } from "mds";
|
||||
import { DialogContentText } from "@mui/material";
|
||||
|
||||
const ConfirmDeleteDestinationModal = ({
|
||||
onConfirm,
|
||||
@@ -25,11 +40,9 @@ const ConfirmDeleteDestinationModal = ({
|
||||
onClose={onClose}
|
||||
confirmationContent={
|
||||
<React.Fragment>
|
||||
<DialogContentText>
|
||||
Are you sure you want to delete the event destination ?
|
||||
<br />
|
||||
<b>{serviceName}</b> which is <b>{status}</b>
|
||||
</DialogContentText>
|
||||
Are you sure you want to delete the event destination ?
|
||||
<br />
|
||||
<b>{serviceName}</b> which is <b>{status}</b>
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -18,17 +18,13 @@ import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import { IElementValue } from "../../Configurations/types";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import CommentBoxWrapper from "../../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import PredefinedList from "../../Common/FormComponents/PredefinedList/PredefinedList";
|
||||
import { Switch, InputBox, Grid, Box, ReadBox, RadioGroup } from "mds";
|
||||
|
||||
interface IConfMySqlProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -138,8 +134,8 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<Switch
|
||||
label={"Enter DNS String"}
|
||||
checked={useDsnString}
|
||||
id="checkedB"
|
||||
@@ -151,7 +147,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
{useDsnString ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="dsn-string"
|
||||
name="dsn_string"
|
||||
label="DSN String"
|
||||
@@ -165,9 +161,17 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.configureString}>
|
||||
<Box
|
||||
withBorders
|
||||
useBackground
|
||||
sx={{
|
||||
overflowY: "auto",
|
||||
height: 170,
|
||||
marginBottom: 12,
|
||||
}}
|
||||
>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="host"
|
||||
name="host"
|
||||
label=""
|
||||
@@ -179,7 +183,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label=""
|
||||
@@ -191,7 +195,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="port"
|
||||
name="port"
|
||||
label=""
|
||||
@@ -204,7 +208,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="user"
|
||||
name="user"
|
||||
label=""
|
||||
@@ -216,7 +220,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="password"
|
||||
name="password"
|
||||
label=""
|
||||
@@ -228,16 +232,17 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
<PredefinedList label={"Connection String"} content={dsnString} />
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
<Grid item xs={12} sx={{ margin: "12px 0" }}>
|
||||
<ReadBox label={"Connection String"} multiLine>
|
||||
{dsnString}
|
||||
</ReadBox>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="table"
|
||||
name="table"
|
||||
label="Table"
|
||||
@@ -250,8 +255,8 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={format}
|
||||
<RadioGroup
|
||||
currentValue={format}
|
||||
id="format"
|
||||
name="format"
|
||||
label="Format"
|
||||
@@ -266,7 +271,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="queue-dir"
|
||||
name="queue_dir"
|
||||
label="Queue Dir"
|
||||
@@ -279,7 +284,7 @@ const ConfMySql = ({ onChange, classes }: IConfMySqlProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="queue-limit"
|
||||
name="queue_limit"
|
||||
label="Queue Limit"
|
||||
|
||||
@@ -18,18 +18,13 @@ import React, { useCallback, useEffect, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import { Box, Grid, InputBox, RadioGroup, ReadBox, Select, Switch } from "mds";
|
||||
import { IElementValue } from "../../Configurations/types";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import CommentBoxWrapper from "../../Common/FormComponents/CommentBoxWrapper/CommentBoxWrapper";
|
||||
import FormSwitchWrapper from "../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import PredefinedList from "../../Common/FormComponents/PredefinedList/PredefinedList";
|
||||
|
||||
interface IConfPostgresProps {
|
||||
onChange: (newValue: IElementValue[]) => void;
|
||||
@@ -205,8 +200,8 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<Switch
|
||||
label={"Manually Configure String"}
|
||||
checked={useConnectionString}
|
||||
id="manualString"
|
||||
@@ -220,7 +215,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
{useConnectionString ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="connection-string"
|
||||
name="connection_string"
|
||||
label="Connection String"
|
||||
@@ -234,9 +229,17 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.configureString}>
|
||||
<Box
|
||||
withBorders
|
||||
useBackground
|
||||
sx={{
|
||||
overflowY: "auto",
|
||||
height: 170,
|
||||
marginBottom: 12,
|
||||
}}
|
||||
>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="host"
|
||||
name="host"
|
||||
label=""
|
||||
@@ -248,7 +251,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="db-name"
|
||||
name="db-name"
|
||||
label=""
|
||||
@@ -260,7 +263,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="port"
|
||||
name="port"
|
||||
label=""
|
||||
@@ -272,14 +275,14 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
<Select
|
||||
value={sslMode}
|
||||
label=""
|
||||
id="sslmode"
|
||||
name="sslmode"
|
||||
onChange={(e): void => {
|
||||
if (e.target.value !== undefined) {
|
||||
setSslMode(e.target.value + "");
|
||||
onChange={(value): void => {
|
||||
if (value) {
|
||||
setSslMode(value + "");
|
||||
}
|
||||
}}
|
||||
options={[
|
||||
@@ -292,7 +295,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="user"
|
||||
name="user"
|
||||
label=""
|
||||
@@ -304,7 +307,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="password"
|
||||
name="password"
|
||||
label=""
|
||||
@@ -316,19 +319,17 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
<PredefinedList
|
||||
label={"Connection String"}
|
||||
content={connectionString}
|
||||
/>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<ReadBox label={"Connection String"} multiLine>
|
||||
{connectionString}
|
||||
</ReadBox>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="table"
|
||||
name="table"
|
||||
label="Table"
|
||||
@@ -341,8 +342,8 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<RadioGroupSelector
|
||||
currentSelection={format}
|
||||
<RadioGroup
|
||||
currentValue={format}
|
||||
id="format"
|
||||
name="format"
|
||||
label="Format"
|
||||
@@ -357,7 +358,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="queue-dir"
|
||||
name="queue_dir"
|
||||
label="Queue Dir"
|
||||
@@ -370,7 +371,7 @@ const ConfPostgres = ({ onChange, classes }: IConfPostgresProps) => {
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="queue-limit"
|
||||
name="queue_limit"
|
||||
label="Queue Limit"
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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 get from "lodash/get";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
|
||||
interface IDestinationButton {
|
||||
destinationType: string;
|
||||
srcImage: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const DestinationButtonBase = styled.button(({ theme }) => ({
|
||||
background: get(theme, "boxBackground", "#FFF"),
|
||||
border: `${get(theme, "borderColor", "#E2E2E2")} 1px solid`,
|
||||
borderRadius: 5,
|
||||
width: 250,
|
||||
height: 80,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "start",
|
||||
marginBottom: 16,
|
||||
marginRight: 8,
|
||||
cursor: "pointer",
|
||||
overflow: "hidden",
|
||||
"&:hover": {
|
||||
backgroundColor: get(theme, "buttons.regular.hover.background", "#ebebeb"),
|
||||
},
|
||||
"& .imageContainer": {
|
||||
width: 80,
|
||||
"& .logoButton": {
|
||||
maxWidth: 46,
|
||||
maxHeight: 46,
|
||||
filter: "drop-shadow(1px 1px 8px #fff)",
|
||||
},
|
||||
},
|
||||
"& .lambdaNotifTitle": {
|
||||
color: get(theme, "buttons.callAction.enabled.background", "#07193E"),
|
||||
fontSize: 16,
|
||||
fontFamily: "Inter,sans-serif",
|
||||
paddingLeft: 18,
|
||||
fontWeight: "bold",
|
||||
},
|
||||
}));
|
||||
|
||||
const DestinationButton = ({
|
||||
destinationType,
|
||||
srcImage,
|
||||
title,
|
||||
}: IDestinationButton) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<DestinationButtonBase
|
||||
onClick={() => {
|
||||
navigate(`${IAM_PAGES.EVENT_DESTINATIONS_ADD}/${destinationType}`);
|
||||
}}
|
||||
>
|
||||
<span className={"imageContainer"}>
|
||||
<img src={srcImage} className={"logoButton"} alt={title} />
|
||||
</span>
|
||||
<span className={"lambdaNotifTitle"}>{title}</span>
|
||||
</DestinationButtonBase>
|
||||
);
|
||||
};
|
||||
|
||||
export default DestinationButton;
|
||||
@@ -15,24 +15,14 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { BackLink, Box, FormLayout, PageLayout } from "mds";
|
||||
import { destinationList, DestType } from "./utils";
|
||||
import {
|
||||
settingsCommon,
|
||||
typesSelection,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { typesSelection } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { Box } from "@mui/material";
|
||||
import NotificationEndpointTypeSelectorHelpBox from "../Account/NotificationEndpointTypeSelectorHelpBox";
|
||||
import { BackLink, PageLayout } from "mds";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
|
||||
interface INotificationTypeSelector {
|
||||
classes: any;
|
||||
}
|
||||
import DestinationButton from "./DestinationButton";
|
||||
|
||||
const withLogos = destinationList.filter((elService) => elService.logo !== "");
|
||||
const database = withLogos.filter(
|
||||
@@ -45,13 +35,7 @@ const functions = withLogos.filter(
|
||||
(elService) => elService.category === DestType.Func
|
||||
);
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...settingsCommon,
|
||||
...typesSelection,
|
||||
});
|
||||
|
||||
const EventTypeSelector = ({ classes }: INotificationTypeSelector) => {
|
||||
const EventTypeSelector = () => {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -67,115 +51,58 @@ const EventTypeSelector = ({ classes }: INotificationTypeSelector) => {
|
||||
actions={<React.Fragment />}
|
||||
/>
|
||||
<PageLayout>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
padding: "16px",
|
||||
gap: "8px",
|
||||
gridTemplateColumns: {
|
||||
md: "2fr 1.2fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
border: "1px solid #eaeaea",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div style={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
<FormLayout helpBox={<NotificationEndpointTypeSelectorHelpBox />}>
|
||||
<Box>
|
||||
<Box sx={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
Queue
|
||||
</div>
|
||||
<div className={classes.iconContainer}>
|
||||
</Box>
|
||||
<Box sx={{ ...typesSelection.iconContainer }}>
|
||||
{queue.map((item) => {
|
||||
return (
|
||||
<button
|
||||
<DestinationButton
|
||||
destinationType={item.actionTrigger}
|
||||
srcImage={item.logo}
|
||||
title={item.targetTitle}
|
||||
key={`icon-${item.targetTitle}`}
|
||||
className={classes.lambdaNotif}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`${IAM_PAGES.EVENT_DESTINATIONS_ADD}/${item.actionTrigger}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={classes.lambdaNotifIcon}>
|
||||
<img
|
||||
src={item.logo}
|
||||
className={classes.logoButton}
|
||||
alt={item.targetTitle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={classes.lambdaNotifTitle}>
|
||||
<b>{item.targetTitle}</b>
|
||||
</div>
|
||||
</button>
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div style={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
</Box>
|
||||
<Box sx={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
Database
|
||||
</div>
|
||||
<div className={classes.iconContainer}>
|
||||
</Box>
|
||||
<Box sx={{ ...typesSelection.iconContainer }}>
|
||||
{database.map((item) => {
|
||||
return (
|
||||
<button
|
||||
<DestinationButton
|
||||
destinationType={item.actionTrigger}
|
||||
srcImage={item.logo}
|
||||
title={item.targetTitle}
|
||||
key={`icon-${item.targetTitle}`}
|
||||
className={classes.lambdaNotif}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`${IAM_PAGES.EVENT_DESTINATIONS_ADD}/${item.actionTrigger}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={classes.lambdaNotifIcon}>
|
||||
<img
|
||||
src={item.logo}
|
||||
className={classes.logoButton}
|
||||
alt={item.targetTitle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={classes.lambdaNotifTitle}>
|
||||
<b>{item.targetTitle}</b>
|
||||
</div>
|
||||
</button>
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div style={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
</Box>
|
||||
<Box sx={{ fontSize: 16, fontWeight: 600, paddingBottom: 15 }}>
|
||||
Functions
|
||||
</div>
|
||||
<div className={classes.iconContainer}>
|
||||
</Box>
|
||||
<Box sx={{ ...typesSelection.iconContainer }}>
|
||||
{functions.map((item) => {
|
||||
return (
|
||||
<button
|
||||
<DestinationButton
|
||||
destinationType={item.actionTrigger}
|
||||
srcImage={item.logo}
|
||||
title={item.targetTitle}
|
||||
key={`icon-${item.targetTitle}`}
|
||||
className={classes.lambdaNotif}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`${IAM_PAGES.EVENT_DESTINATIONS_ADD}/${item.actionTrigger}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={classes.lambdaNotifIcon}>
|
||||
<img
|
||||
src={item.logo}
|
||||
className={classes.logoButton}
|
||||
alt={item.targetTitle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={classes.lambdaNotifTitle}>
|
||||
<b>{item.targetTitle}</b>
|
||||
</div>
|
||||
</button>
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<NotificationEndpointTypeSelectorHelpBox />
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</FormLayout>
|
||||
</PageLayout>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(EventTypeSelector);
|
||||
export default EventTypeSelector;
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
AddIcon,
|
||||
Box,
|
||||
Button,
|
||||
DataTable,
|
||||
Grid,
|
||||
HelpBox,
|
||||
LambdaIcon,
|
||||
PageLayout,
|
||||
@@ -30,7 +32,6 @@ import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { red } from "@mui/material/colors";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
||||
import {
|
||||
NotificationEndpointItem,
|
||||
@@ -38,7 +39,6 @@ import {
|
||||
TransformedEndpointItem,
|
||||
} from "./types";
|
||||
import { getNotificationConfigKey, notificationTransform } from "./utils";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
|
||||
import {
|
||||
actionsTray,
|
||||
@@ -57,9 +57,11 @@ import {
|
||||
setErrorSnackMessage,
|
||||
setServerNeedsRestart,
|
||||
} from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import ConfirmDeleteDestinationModal from "./ConfirmDeleteDestinationModal";
|
||||
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
|
||||
import { useSelector } from "react-redux";
|
||||
import { setDestinationLoading } from "./destinationsSlice";
|
||||
|
||||
interface IListNotificationEndpoints {
|
||||
classes: any;
|
||||
@@ -70,9 +72,6 @@ const styles = (theme: Theme) =>
|
||||
...actionsTray,
|
||||
...settingsCommon,
|
||||
...containerForHeader,
|
||||
twHeight: {
|
||||
minHeight: 400,
|
||||
},
|
||||
tableBlock: {
|
||||
...tableStyles.tableBlock,
|
||||
},
|
||||
@@ -92,10 +91,12 @@ const styles = (theme: Theme) =>
|
||||
const ListEventDestinations = ({ classes }: IListNotificationEndpoints) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
// Reducer States
|
||||
const isLoading = useSelector((state: AppState) => state.destination.loading);
|
||||
|
||||
//Local States
|
||||
const [records, setRecords] = useState<TransformedEndpointItem[]>([]);
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const [isDelConfirmOpen, setIsDelConfirmOpen] = useState<boolean>(false);
|
||||
const [selNotifyEndPoint, setSelNotifyEndpoint] =
|
||||
@@ -114,11 +115,11 @@ const ListEventDestinations = ({ classes }: IListNotificationEndpoints) => {
|
||||
resNotEndList = res.notification_endpoints;
|
||||
}
|
||||
setRecords(notificationTransform(resNotEndList));
|
||||
setIsLoading(false);
|
||||
dispatch(setDestinationLoading(false));
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
setIsLoading(false);
|
||||
dispatch(setDestinationLoading(false));
|
||||
});
|
||||
};
|
||||
fetchRecords();
|
||||
@@ -126,8 +127,8 @@ const ListEventDestinations = ({ classes }: IListNotificationEndpoints) => {
|
||||
}, [isLoading, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
}, []);
|
||||
dispatch(setDestinationLoading(true));
|
||||
}, [dispatch]);
|
||||
|
||||
const resetNotificationConfig = (
|
||||
ep: TransformedEndpointItem | undefined | null
|
||||
@@ -142,6 +143,7 @@ const ListEventDestinations = ({ classes }: IListNotificationEndpoints) => {
|
||||
dispatch(setServerNeedsRestart(true));
|
||||
setSelNotifyEndpoint(null);
|
||||
setIsDelConfirmOpen(false);
|
||||
dispatch(setDestinationLoading(true));
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setIsDelConfirmOpen(false);
|
||||
@@ -188,142 +190,146 @@ const ListEventDestinations = ({ classes }: IListNotificationEndpoints) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageLayout>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<SearchBox
|
||||
placeholder="Search target"
|
||||
onChange={setFilter}
|
||||
overrideClass={classes.searchField}
|
||||
value={filter}
|
||||
/>
|
||||
<div className={classes.rightActionItems}>
|
||||
<TooltipWrapper tooltip={"Refresh List"}>
|
||||
<Button
|
||||
id={"reload-event-destinations"}
|
||||
label={"Refresh"}
|
||||
variant="regular"
|
||||
icon={<RefreshIcon />}
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper tooltip={"Add Event Destination"}>
|
||||
<Button
|
||||
id={"add-notification-target"}
|
||||
label={"Add Event Destination"}
|
||||
variant="callAction"
|
||||
icon={<AddIcon />}
|
||||
onClick={() => {
|
||||
navigate(IAM_PAGES.EVENT_DESTINATIONS_ADD);
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Grid>
|
||||
{isLoading && <LinearProgress />}
|
||||
{!isLoading && (
|
||||
<Fragment>
|
||||
{records.length > 0 && (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{
|
||||
label: "Status",
|
||||
elementKey: "status",
|
||||
renderFunction: statusDisplay,
|
||||
width: 150,
|
||||
},
|
||||
{ label: "Service", elementKey: "service_name" },
|
||||
]}
|
||||
isLoading={isLoading}
|
||||
records={filteredRecords}
|
||||
entityName="Event Destinations"
|
||||
idField="service_name"
|
||||
customPaperHeight={classes.twHeight}
|
||||
<Grid container sx={{ width: "100%" }}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<SearchBox
|
||||
placeholder="Search target"
|
||||
onChange={setFilter}
|
||||
overrideClass={classes.searchField}
|
||||
value={filter}
|
||||
/>
|
||||
<div className={classes.rightActionItems}>
|
||||
<TooltipWrapper tooltip={"Refresh List"}>
|
||||
<Button
|
||||
id={"reload-event-destinations"}
|
||||
label={"Refresh"}
|
||||
variant="regular"
|
||||
icon={<RefreshIcon />}
|
||||
onClick={() => {
|
||||
dispatch(setDestinationLoading(true));
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper tooltip={"Add Event Destination"}>
|
||||
<Button
|
||||
id={"add-notification-target"}
|
||||
label={"Add Event Destination"}
|
||||
variant="callAction"
|
||||
icon={<AddIcon />}
|
||||
onClick={() => {
|
||||
navigate(IAM_PAGES.EVENT_DESTINATIONS_ADD);
|
||||
}}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Grid>
|
||||
{isLoading && <LinearProgress />}
|
||||
{!isLoading && (
|
||||
<Fragment>
|
||||
{records.length > 0 && (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<DataTable
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{
|
||||
label: "Status",
|
||||
elementKey: "status",
|
||||
renderFunction: statusDisplay,
|
||||
width: 150,
|
||||
},
|
||||
{ label: "Service", elementKey: "service_name" },
|
||||
]}
|
||||
isLoading={isLoading}
|
||||
records={filteredRecords}
|
||||
entityName="Event Destinations"
|
||||
idField="service_name"
|
||||
customPaperHeight={"400px"}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{ marginTop: 15 }}>
|
||||
<HelpBox
|
||||
title={"Event Destinations"}
|
||||
iconComponent={<LambdaIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO bucket notifications allow administrators to
|
||||
send notifications to supported external services on
|
||||
certain object or bucket events. MinIO supports bucket
|
||||
and object-level S3 events similar to the Amazon S3
|
||||
Event Notifications.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
<a
|
||||
href="https://min.io/docs/minio/linux/administration/monitoring/bucket-notifications.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
)}
|
||||
{records.length === 0 && (
|
||||
<Grid
|
||||
container
|
||||
sx={{
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Grid item xs={8}>
|
||||
<HelpBox
|
||||
title={"Event Destinations"}
|
||||
iconComponent={<LambdaIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO bucket notifications allow administrators to
|
||||
send notifications to supported external services on
|
||||
certain object or bucket events. MinIO supports bucket
|
||||
and object-level S3 events similar to the Amazon S3
|
||||
Event Notifications.
|
||||
<br />
|
||||
<br />
|
||||
To get started,{" "}
|
||||
<AButton
|
||||
onClick={() => {
|
||||
navigate(IAM_PAGES.EVENT_DESTINATIONS_ADD);
|
||||
}}
|
||||
>
|
||||
Add an Event Destination
|
||||
</AButton>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<HelpBox
|
||||
title={"Event Destinations"}
|
||||
iconComponent={<LambdaIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO bucket notifications allow administrators to send
|
||||
notifications to supported external services on certain
|
||||
object or bucket events. MinIO supports bucket and
|
||||
object-level S3 events similar to the Amazon S3 Event
|
||||
Notifications.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
<a
|
||||
href="https://min.io/docs/minio/linux/administration/monitoring/bucket-notifications.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
)}
|
||||
{records.length === 0 && (
|
||||
<Grid
|
||||
container
|
||||
justifyContent={"center"}
|
||||
alignContent={"center"}
|
||||
alignItems={"center"}
|
||||
>
|
||||
<Grid item xs={8}>
|
||||
<HelpBox
|
||||
title={"Event Destinations"}
|
||||
iconComponent={<LambdaIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO bucket notifications allow administrators to send
|
||||
notifications to supported external services on certain
|
||||
object or bucket events. MinIO supports bucket and
|
||||
object-level S3 events similar to the Amazon S3 Event
|
||||
Notifications.
|
||||
<br />
|
||||
<br />
|
||||
To get started,{" "}
|
||||
<AButton
|
||||
onClick={() => {
|
||||
navigate(IAM_PAGES.EVENT_DESTINATIONS_ADD);
|
||||
}}
|
||||
>
|
||||
Add an Event Destination
|
||||
</AButton>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{isDelConfirmOpen ? (
|
||||
<ConfirmDeleteDestinationModal
|
||||
onConfirm={() => {
|
||||
resetNotificationConfig(selNotifyEndPoint);
|
||||
}}
|
||||
status={`${selNotifyEndPoint?.status}`}
|
||||
serviceName={`${selNotifyEndPoint?.service_name}`}
|
||||
onClose={() => {
|
||||
setIsDelConfirmOpen(false);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{isDelConfirmOpen ? (
|
||||
<ConfirmDeleteDestinationModal
|
||||
onConfirm={() => {
|
||||
resetNotificationConfig(selNotifyEndPoint);
|
||||
}}
|
||||
status={`${selNotifyEndPoint?.status}`}
|
||||
serviceName={`${selNotifyEndPoint?.service_name}`}
|
||||
onClose={() => {
|
||||
setIsDelConfirmOpen(false);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</Grid>
|
||||
</PageLayout>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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 get from "lodash/get";
|
||||
import styled from "styled-components";
|
||||
import { Box } from "mds";
|
||||
|
||||
interface ITargetTitle {
|
||||
logoSrc: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const TargetBase = styled.div(({ theme }) => ({
|
||||
background: get(theme, "boxBackground", "#fff"),
|
||||
border: `${get(theme, "borderColor", "#E5E5E5")} 1px solid`,
|
||||
borderRadius: 5,
|
||||
height: 80,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "start",
|
||||
marginBottom: 16,
|
||||
cursor: "pointer",
|
||||
padding: 0,
|
||||
overflow: "hidden",
|
||||
"& .logoButton": {
|
||||
height: "80px",
|
||||
},
|
||||
"& .imageContainer": {
|
||||
backgroundColor: get(theme, "bgColor", "#fff"),
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 80,
|
||||
height: 80,
|
||||
|
||||
"& img": {
|
||||
maxWidth: 46,
|
||||
maxHeight: 46,
|
||||
filter: "drop-shadow(1px 1px 8px #fff)",
|
||||
},
|
||||
},
|
||||
"& .titleBox": {
|
||||
color: get(theme, "fontColor", "#000"),
|
||||
fontSize: 16,
|
||||
fontFamily: "Inter,sans-serif",
|
||||
paddingLeft: 18,
|
||||
},
|
||||
}));
|
||||
|
||||
const TargetTitle = ({ logoSrc, title }: ITargetTitle) => {
|
||||
return (
|
||||
<TargetBase>
|
||||
<Box className={"imageContainer"}>
|
||||
<img src={logoSrc} className={"logoButton"} alt={title} />
|
||||
</Box>
|
||||
|
||||
<Box className={"titleBox"}>
|
||||
<b>{title} Event Destination</b>
|
||||
</Box>
|
||||
</TargetBase>
|
||||
);
|
||||
};
|
||||
|
||||
export default TargetTitle;
|
||||
@@ -0,0 +1,40 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2023 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 { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
export interface DestinationState {
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const initialState: DestinationState = {
|
||||
loading: true,
|
||||
};
|
||||
|
||||
export const destinationSlice = createSlice({
|
||||
name: "destination",
|
||||
initialState,
|
||||
reducers: {
|
||||
setDestinationLoading: (state, action: PayloadAction<boolean>) => {
|
||||
state.loading = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { setDestinationLoading } = destinationSlice.actions;
|
||||
|
||||
export default destinationSlice.reducer;
|
||||
@@ -30,6 +30,7 @@ import dashboardReducer from "./screens/Console/Dashboard/dashboardSlice";
|
||||
import createUserReducer from "./screens/Console/Users/AddUsersSlice";
|
||||
import licenseReducer from "./screens/Console/License/licenseSlice";
|
||||
import registerReducer from "./screens/Console/Support/registerSlice";
|
||||
import destinationSlice from "./screens/Console/EventDestinations/destinationsSlice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
system: systemReducer,
|
||||
@@ -46,6 +47,7 @@ const rootReducer = combineReducers({
|
||||
register: registerReducer,
|
||||
createUser: createUserReducer,
|
||||
license: licenseReducer,
|
||||
destination: destinationSlice,
|
||||
});
|
||||
|
||||
export const store = configureStore({
|
||||
|
||||
Reference in New Issue
Block a user