Updated Audit Logs page to use mds (#2897)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -15,9 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { Button, OpenListIcon, SyncIcon } from "mds";
|
||||
import { Button, OpenListIcon, SyncIcon, Grid } from "mds";
|
||||
import { DateTime } from "luxon";
|
||||
import { Box, Grid } from "@mui/material";
|
||||
import { Box } from "@mui/material";
|
||||
import ScheduleIcon from "@mui/icons-material/Schedule";
|
||||
import WatchLaterIcon from "@mui/icons-material/WatchLater";
|
||||
import DateTimePickerWrapper from "../DateTimePickerWrapper/DateTimePickerWrapper";
|
||||
|
||||
@@ -15,14 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { searchField } from "../common/styleLibrary";
|
||||
import { InputBox, InputLabel, Box } from "mds";
|
||||
|
||||
interface IFilterInputWrapper {
|
||||
classes: any;
|
||||
value: string;
|
||||
onChange: (txtVar: string) => any;
|
||||
label: string;
|
||||
@@ -31,45 +26,7 @@ interface IFilterInputWrapper {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
searchField: {
|
||||
...searchField.searchField,
|
||||
height: 30,
|
||||
padding: 0,
|
||||
"& input": {
|
||||
padding: "0 12px",
|
||||
height: 28,
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: "#393939",
|
||||
},
|
||||
"&.isDisabled": {
|
||||
"&:hover": {
|
||||
borderColor: "#EAEDEE",
|
||||
},
|
||||
},
|
||||
"& input.Mui-disabled": {
|
||||
backgroundColor: "#EAEAEA",
|
||||
},
|
||||
},
|
||||
labelStyle: {
|
||||
color: "#393939",
|
||||
fontSize: 12,
|
||||
marginBottom: 4,
|
||||
},
|
||||
buttonKit: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
fieldContainer: {
|
||||
flexGrow: 1,
|
||||
margin: "0 15px",
|
||||
},
|
||||
});
|
||||
|
||||
const FilterInputWrapper = ({
|
||||
classes,
|
||||
label,
|
||||
onChange,
|
||||
value,
|
||||
@@ -79,27 +36,31 @@ const FilterInputWrapper = ({
|
||||
}: IFilterInputWrapper) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.fieldContainer}>
|
||||
<div className={classes.labelStyle}>{label}</div>
|
||||
<div className={classes.buttonKit}>
|
||||
<TextField
|
||||
placeholder={placeholder}
|
||||
id={id}
|
||||
name={name}
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
onChange(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
className={classes.searchField}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Box
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
margin: "0 15px",
|
||||
}}
|
||||
>
|
||||
<InputLabel>{label}</InputLabel>
|
||||
<InputBox
|
||||
placeholder={placeholder}
|
||||
id={id}
|
||||
name={name}
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
onChange(val.target.value);
|
||||
}}
|
||||
sx={{
|
||||
"& input": {
|
||||
height: 30,
|
||||
},
|
||||
}}
|
||||
value={value}
|
||||
/>
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(FilterInputWrapper);
|
||||
export default FilterInputWrapper;
|
||||
|
||||
@@ -15,14 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { Grid } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Button } from "mds";
|
||||
import { Button, Grid } from "mds";
|
||||
import get from "lodash/get";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { IReqInfoSearchResults } from "./types";
|
||||
import { LogSearchColumnLabels } from "./utils";
|
||||
|
||||
@@ -30,27 +25,12 @@ interface ILogSearchFullModal {
|
||||
modalOpen: boolean;
|
||||
logSearchElement: IReqInfoSearchResults;
|
||||
onClose: () => void;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
objectKeyCol: {
|
||||
fontWeight: 700,
|
||||
paddingRight: "10px",
|
||||
textAlign: "left",
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const LogSearchFullModal = ({
|
||||
modalOpen,
|
||||
logSearchElement,
|
||||
onClose,
|
||||
classes,
|
||||
}: ILogSearchFullModal) => {
|
||||
const jsonItems = Object.keys(logSearchElement);
|
||||
|
||||
@@ -69,7 +49,13 @@ const LogSearchFullModal = ({
|
||||
<tbody>
|
||||
{jsonItems.map((objectKey: string, index: number) => (
|
||||
<tr key={`logSearch-${index.toString()}`}>
|
||||
<th className={classes.objectKeyCol}>
|
||||
<th
|
||||
style={{
|
||||
fontWeight: 700,
|
||||
paddingRight: "10px",
|
||||
textAlign: "left",
|
||||
}}
|
||||
>
|
||||
{get(LogSearchColumnLabels, objectKey, `${objectKey}`)}
|
||||
</th>
|
||||
<td>{get(logSearchElement, objectKey, "")}</td>
|
||||
@@ -78,7 +64,11 @@ const LogSearchFullModal = ({
|
||||
</tbody>
|
||||
</table>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{ display: "flex", justifyContent: "flex-end" }}
|
||||
>
|
||||
<Button
|
||||
id={"close-log-search"}
|
||||
variant="callAction"
|
||||
@@ -93,4 +83,4 @@ const LogSearchFullModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(LogSearchFullModal);
|
||||
export default LogSearchFullModal;
|
||||
|
||||
@@ -15,112 +15,47 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Button, PageLayout, SearchIcon } from "mds";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Grid } from "@mui/material";
|
||||
import { DateTime } from "luxon";
|
||||
import get from "lodash/get";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { useSelector } from "react-redux";
|
||||
import { CSSObject } from "styled-components";
|
||||
import {
|
||||
advancedFilterToggleStyles,
|
||||
containerForHeader,
|
||||
tableStyles,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
Box,
|
||||
breakPoints,
|
||||
Button,
|
||||
DataTable,
|
||||
ExpandOptionsButton,
|
||||
Grid,
|
||||
PageLayout,
|
||||
SearchIcon,
|
||||
} from "mds";
|
||||
import { DateTime } from "luxon";
|
||||
import { IReqInfoSearchResults, ISearchResponse } from "./types";
|
||||
import { niceBytes, nsToSeconds } from "../../../../common/utils";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import api from "../../../../common/api";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import FilterInputWrapper from "../../Common/FormComponents/FilterInputWrapper/FilterInputWrapper";
|
||||
import LogSearchFullModal from "./LogSearchFullModal";
|
||||
import { LogSearchColumnLabels } from "./utils";
|
||||
import DateRangeSelector from "../../Common/FormComponents/DateRangeSelector/DateRangeSelector";
|
||||
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
|
||||
import {
|
||||
CONSOLE_UI_RESOURCE,
|
||||
IAM_SCOPES,
|
||||
} from "../../../../common/SecureComponent/permissions";
|
||||
import { SecureComponent } from "../../../../common/SecureComponent";
|
||||
import MissingIntegration from "../../Common/MissingIntegration/MissingIntegration";
|
||||
import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice";
|
||||
import { selFeatures } from "../../consoleSlice";
|
||||
import { useAppDispatch } from "../../../../store";
|
||||
import { SecureComponent } from "../../../../common/SecureComponent";
|
||||
import api from "../../../../common/api";
|
||||
import FilterInputWrapper from "../../Common/FormComponents/FilterInputWrapper/FilterInputWrapper";
|
||||
import LogSearchFullModal from "./LogSearchFullModal";
|
||||
import DateRangeSelector from "../../Common/FormComponents/DateRangeSelector/DateRangeSelector";
|
||||
import MissingIntegration from "../../Common/MissingIntegration/MissingIntegration";
|
||||
import PageHeaderWrapper from "../../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../../HelpMenu";
|
||||
|
||||
interface ILogSearchProps {
|
||||
classes: any;
|
||||
}
|
||||
const filtersContainer: CSSObject = {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 12,
|
||||
};
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
blockCollapsed: {
|
||||
display: "none",
|
||||
overflowY: "hidden",
|
||||
},
|
||||
filterOpen: {
|
||||
display: "block",
|
||||
marginBottom: 12,
|
||||
},
|
||||
endLineAction: {
|
||||
marginBottom: 15,
|
||||
padding: "0 15px 0 15px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
filtersContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: 12,
|
||||
},
|
||||
innerContainer: {
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
noticeLabel: {
|
||||
marginLeft: 15,
|
||||
marginBottom: 15,
|
||||
fontSize: 12,
|
||||
color: "#9C9C9C",
|
||||
},
|
||||
|
||||
tableFOpen: {
|
||||
height: "calc(100vh - 520px)",
|
||||
},
|
||||
tableFClosed: {
|
||||
height: "calc(100vh - 320px)",
|
||||
},
|
||||
...tableStyles,
|
||||
...advancedFilterToggleStyles,
|
||||
|
||||
searchOptions: {
|
||||
display: "flex",
|
||||
padding: 15,
|
||||
"@media (max-width: 900px)": {
|
||||
flexFlow: "column",
|
||||
},
|
||||
},
|
||||
formBox: {
|
||||
border: "1px solid #EAEAEA",
|
||||
marginBottom: 15,
|
||||
},
|
||||
dateRangePicker: {
|
||||
"& div": {
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
advancedButton: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
},
|
||||
|
||||
...containerForHeader,
|
||||
});
|
||||
|
||||
const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
const LogsSearchMain = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useSelector(selFeatures);
|
||||
|
||||
@@ -239,16 +174,19 @@ const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
const selectColumn = (colName: string, active: boolean) => {
|
||||
let newArray = [...columnsShown];
|
||||
const selectColumn = (colID: string) => {
|
||||
let newArray: string[];
|
||||
|
||||
if (!active) {
|
||||
newArray = columnsShown.filter((element) => element !== colName);
|
||||
const columnShown = columnsShown.findIndex((item) => item === colID);
|
||||
|
||||
// Column Exist, We remove from Array
|
||||
if (columnShown >= 0) {
|
||||
newArray = columnsShown.filter((element) => element !== colID);
|
||||
} else {
|
||||
if (!newArray.includes(colName)) {
|
||||
newArray.push(colName);
|
||||
}
|
||||
// Column not visible, we include it in the array
|
||||
newArray = [...columnsShown, colID];
|
||||
}
|
||||
|
||||
setColumnsShown(newArray);
|
||||
};
|
||||
|
||||
@@ -298,113 +236,129 @@ const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
<MissingIntegration
|
||||
entity={"Audit Logs"}
|
||||
iconComponent={<SearchIcon />}
|
||||
documentationLink="https://github.com/minio/operator/tree/master/logsearchapi"
|
||||
documentationLink="https://min.io/docs/minio/windows/operations/monitoring/minio-logging.html?ref=con"
|
||||
/>
|
||||
) : (
|
||||
<Fragment>
|
||||
{" "}
|
||||
<Grid item xs={12} className={classes.formBox}>
|
||||
<Grid item xs={12} className={`${classes.searchOptions}`}>
|
||||
<div className={classes.dateRangePicker}>
|
||||
<Box withBorders sx={{ marginBottom: 15 }}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
display: "flex",
|
||||
padding: 15,
|
||||
[`@media (max-width: ${breakPoints.lg}px)`]: {
|
||||
flexFlow: "column",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<DateRangeSelector
|
||||
setTimeEnd={(time) => setTimeEnd(time)}
|
||||
setTimeStart={(time) => setTimeStart(time)}
|
||||
timeEnd={timeEnd}
|
||||
timeStart={timeStart}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Grid item className={classes.advancedButton}>
|
||||
<button
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<ExpandOptionsButton
|
||||
label={`${filterOpen ? "Hide" : "Show"} advanced Filters`}
|
||||
open={filterOpen}
|
||||
onClick={() => {
|
||||
setFilterOpen(!filterOpen);
|
||||
}}
|
||||
className={classes.advancedConfiguration}
|
||||
>
|
||||
{filterOpen ? "Hide" : "Show"} advanced Filters{" "}
|
||||
<span
|
||||
className={
|
||||
filterOpen
|
||||
? classes.advancedOpen
|
||||
: classes.advancedClosed
|
||||
}
|
||||
>
|
||||
<ArrowForwardIosIcon />
|
||||
</span>
|
||||
</button>
|
||||
</Grid>
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.blockCollapsed} ${
|
||||
filterOpen ? classes.filterOpen : ""
|
||||
}`}
|
||||
sx={{
|
||||
display: filterOpen ? "block" : "none",
|
||||
overflowY: "hidden",
|
||||
marginBottom: filterOpen ? 12 : 0,
|
||||
}}
|
||||
>
|
||||
<div className={classes.innerContainer}>
|
||||
<div className={classes.noticeLabel}>
|
||||
Enable your preferred options to get filtered records.
|
||||
<br />
|
||||
You can use '*' to match any character, '.' to signify a
|
||||
single character or '\' to scape an special character (E.g.
|
||||
mybucket-*)
|
||||
</div>
|
||||
<div className={classes.filtersContainer}>
|
||||
<FilterInputWrapper
|
||||
onChange={setBucket}
|
||||
value={bucket}
|
||||
label={"Bucket"}
|
||||
id="bucket"
|
||||
name="bucket"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setApiName}
|
||||
value={apiName}
|
||||
label={"API Name"}
|
||||
id="api_name"
|
||||
name="api_name"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setAccessKey}
|
||||
value={accessKey}
|
||||
label={"Access Key"}
|
||||
id="access_key"
|
||||
name="access_key"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setUserAgent}
|
||||
value={userAgent}
|
||||
label={"User Agent"}
|
||||
id="user_agent"
|
||||
name="user_agent"
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.filtersContainer}>
|
||||
<FilterInputWrapper
|
||||
onChange={setObject}
|
||||
value={object}
|
||||
label={"Object"}
|
||||
id="object"
|
||||
name="object"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setRequestID}
|
||||
value={requestID}
|
||||
label={"Request ID"}
|
||||
id="request_id"
|
||||
name="request_id"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setResponseStatus}
|
||||
value={responseStatus}
|
||||
label={"Response Status"}
|
||||
id="response_status"
|
||||
name="response_status"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Box
|
||||
sx={{
|
||||
marginLeft: 15,
|
||||
marginBottom: 15,
|
||||
fontSize: 12,
|
||||
color: "#9C9C9C",
|
||||
}}
|
||||
>
|
||||
Enable your preferred options to get filtered records.
|
||||
<br />
|
||||
You can use '*' to match any character, '.' to signify a
|
||||
single character or '\' to scape an special character (E.g.
|
||||
mybucket-*)
|
||||
</Box>
|
||||
<Box sx={filtersContainer}>
|
||||
<FilterInputWrapper
|
||||
onChange={setBucket}
|
||||
value={bucket}
|
||||
label={"Bucket"}
|
||||
id="bucket"
|
||||
name="bucket"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setApiName}
|
||||
value={apiName}
|
||||
label={"API Name"}
|
||||
id="api_name"
|
||||
name="api_name"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setAccessKey}
|
||||
value={accessKey}
|
||||
label={"Access Key"}
|
||||
id="access_key"
|
||||
name="access_key"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setUserAgent}
|
||||
value={userAgent}
|
||||
label={"User Agent"}
|
||||
id="user_agent"
|
||||
name="user_agent"
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={filtersContainer}>
|
||||
<FilterInputWrapper
|
||||
onChange={setObject}
|
||||
value={object}
|
||||
label={"Object"}
|
||||
id="object"
|
||||
name="object"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setRequestID}
|
||||
value={requestID}
|
||||
label={"Request ID"}
|
||||
id="request_id"
|
||||
name="request_id"
|
||||
/>
|
||||
<FilterInputWrapper
|
||||
onChange={setResponseStatus}
|
||||
value={responseStatus}
|
||||
label={"Response Status"}
|
||||
id="response_status"
|
||||
name="response_status"
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.endLineAction}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
marginBottom: 15,
|
||||
padding: "0 15px 0 15px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
id={"get-information"}
|
||||
type="button"
|
||||
@@ -413,14 +367,14 @@ const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
label={"Get Information"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
</Box>
|
||||
<Grid item xs={12}>
|
||||
<SecureComponent
|
||||
scopes={[IAM_SCOPES.ADMIN_HEALTH_INFO]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
<DataTable
|
||||
columns={[
|
||||
{
|
||||
label: LogSearchColumnLabels.time,
|
||||
@@ -496,7 +450,7 @@ const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
columnsShown={columnsShown}
|
||||
onColumnChange={selectColumn}
|
||||
customPaperHeight={
|
||||
filterOpen ? classes.tableFOpen : classes.tableFClosed
|
||||
filterOpen ? "calc(100vh - 520px)" : "calc(100vh - 320px)"
|
||||
}
|
||||
sortConfig={{
|
||||
currentSort: "time",
|
||||
@@ -524,4 +478,4 @@ const LogsSearchMain = ({ classes }: ILogSearchProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(LogsSearchMain);
|
||||
export default LogsSearchMain;
|
||||
|
||||
Reference in New Issue
Block a user