Tools Page (#1180)
* Tools Page Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Help Boxes Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Remove Un-Used code Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -79,4 +79,4 @@ clean:
|
||||
@rm -vf console
|
||||
|
||||
docker:
|
||||
@docker build -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
|
||||
@docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' .
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="227.615" height="256" viewBox="0 0 227.615 256">
|
||||
<g id="lambda-icn" transform="translate(-89.849 -94.42)">
|
||||
<path id="Trazado_442" data-name="Trazado 442" d="M71.316,41.17a15.363,15.363,0,0,0,0,30.727c23.352,0,32.017,14.872,40.928,34.353l1.475,3.134c1.229,2.643,3.872,8.542,7.436,16.408L37.271,274.264A15.363,15.363,0,0,0,64,289.382l72.823-128.623c19.481,44,44,99.494,44.431,100.415A58.2,58.2,0,0,0,252.3,294.544a15.375,15.375,0,0,0-9.1-29.375,27.531,27.531,0,0,1-33.861-16.593c-2.458-5.531-59.856-135.751-67.6-152.282l-1.352-2.95C132.462,76.506,116.3,41.17,71.316,41.17Z" transform="translate(54.335 53.25)" fill="#020202"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 692 B |
@@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="236.312" height="256" viewBox="0 0 236.312 256">
|
||||
<g id="tiers-icn" transform="translate(-34.003 -3)">
|
||||
<g id="tiers" transform="translate(34.003 3)">
|
||||
<path id="Trazado_441" data-name="Trazado 441" d="M122.387,3a9.847,9.847,0,0,0-5.154,1.308L8.925,66.851a9.847,9.847,0,0,0,0,17.039l33.4,19.289-33.4,19.289a9.847,9.847,0,0,0,0,17.058l33.4,19.27-33.4,19.289a9.847,9.847,0,0,0,0,17.058l108.308,62.54a9.847,9.847,0,0,0,9.846,0l108.308-62.54a9.847,9.847,0,0,0,0-17.058l-33.4-19.289,33.4-19.27a9.847,9.847,0,0,0,0-17.058l-33.4-19.289,33.4-19.289a9.847,9.847,0,0,0,0-17.039L127.079,4.311A9.847,9.847,0,0,0,122.387,3ZM62.041,114.563l55.192,31.866a9.847,9.847,0,0,0,9.846,0l55.192-31.866,28.5,16.443L122.156,182.16,33.54,131.006Zm-.02,55.617,55.212,31.866a9.847,9.847,0,0,0,9.846,0l55.212-31.866,28.481,16.443-88.615,51.155L33.54,186.622Z" transform="translate(-4 -3)"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 942 B |
9
iconos/Tools.svg
Normal file
9
iconos/Tools.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="16.986" viewBox="0 0 17 16.986">
|
||||
<g id="Tools" transform="translate(-56.747 -82.596)">
|
||||
<g id="Grupo_1868" data-name="Grupo 1868">
|
||||
<path id="Trazado_6843" data-name="Trazado 6843" d="M71.847,82.6,68.6,84.36l.016.961-2.387,2.387,2.411,2.411,2.42-2.42.871,0,1.82-3.206Z" fill="#bccee6"/>
|
||||
<path id="Trazado_6844" data-name="Trazado 6844" d="M61.539,92.4l-4.525,4.525a.852.852,0,0,0,0,1.205l1.205,1.206a.853.853,0,0,0,1.206,0l4.524-4.525Z" fill="#bccee6"/>
|
||||
</g>
|
||||
<path id="Trazado_6845" data-name="Trazado 6845" d="M73.162,96.921l-9.736-9.735a3.381,3.381,0,0,0-4.152-4.153L61.343,85.1l-2.411,2.411-2.069-2.069A3.381,3.381,0,0,0,61.016,89.6l9.735,9.736a.853.853,0,0,0,1.206,0l1.205-1.206A.852.852,0,0,0,73.162,96.921Z" fill="#bccee6"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 828 B |
@@ -67,11 +67,13 @@ var (
|
||||
remoteBuckets = "/remote-buckets"
|
||||
replication = "/replication"
|
||||
license = "/license"
|
||||
watch = "/watch"
|
||||
heal = "/heal"
|
||||
trace = "/trace"
|
||||
logs = "/logs"
|
||||
healthInfo = "/health-info"
|
||||
watch = "/tools/watch"
|
||||
heal = "/tools/heal"
|
||||
trace = "/tools/trace"
|
||||
tools = "/tools"
|
||||
logs = "/tools/logs"
|
||||
auditLogs = "/tools/audit-logs"
|
||||
healthInfo = "/tools/diagnostics"
|
||||
)
|
||||
|
||||
type ConfigurationActionSet struct {
|
||||
@@ -261,6 +263,16 @@ var logsActionSet = ConfigurationActionSet{
|
||||
),
|
||||
}
|
||||
|
||||
// toolsActionSet contains the list of admin actions required for this endpoint to work
|
||||
var toolsActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
iampolicy.AllAdminActions,
|
||||
),
|
||||
actions: iampolicy.NewActionSet(
|
||||
iampolicy.ConsoleLogAdminAction,
|
||||
),
|
||||
}
|
||||
|
||||
// traceActionSet contains the list of admin actions required for this endpoint to work
|
||||
var traceActionSet = ConfigurationActionSet{
|
||||
actionTypes: iampolicy.NewActionSet(
|
||||
@@ -327,6 +339,8 @@ var endpointRules = map[string]ConfigurationActionSet{
|
||||
heal: healActionSet,
|
||||
trace: traceActionSet,
|
||||
logs: logsActionSet,
|
||||
auditLogs: logsActionSet,
|
||||
tools: toolsActionSet,
|
||||
healthInfo: healthInfoActionSet,
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"admin:*",
|
||||
},
|
||||
},
|
||||
want: 30,
|
||||
want: 32,
|
||||
},
|
||||
{
|
||||
name: "all s3 endpoints",
|
||||
@@ -89,7 +89,7 @@ func TestGetAuthorizedEndpoints(t *testing.T) {
|
||||
"s3:*",
|
||||
},
|
||||
},
|
||||
want: 32,
|
||||
want: 34,
|
||||
},
|
||||
{
|
||||
name: "Console User - default endpoints",
|
||||
|
||||
@@ -27,6 +27,10 @@ const styles = (theme: Theme) =>
|
||||
link: {
|
||||
textDecoration: "none",
|
||||
color: theme.palette.primary.main,
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
marginBottom: 10,
|
||||
marginTop: 10,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
export default function Title(props: React.Props<any>) {
|
||||
return (
|
||||
<Typography component="h2" variant="h6" color="primary" gutterBottom>
|
||||
{props.children}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
Title.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import React from "react";
|
||||
import { SvgIcon, SvgIconProps } from "@mui/material";
|
||||
import { IIcon } from "./props";
|
||||
|
||||
const DeleteIcon = (props: SvgIconProps) => {
|
||||
return (
|
||||
|
||||
45
portal-ui/src/icons/ToolsIcon.tsx
Normal file
45
portal-ui/src/icons/ToolsIcon.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import * as React from "react";
|
||||
import { SvgIcon, SvgIconProps } from "@mui/material";
|
||||
|
||||
const ToolsIcon = (props: SvgIconProps) => {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 16.986">
|
||||
<g fill="#bccee6">
|
||||
<g data-name="Grupo 1868">
|
||||
<path
|
||||
data-name="Trazado 6843"
|
||||
d="M15.1.004l-3.247 1.76.016.961-2.387 2.387 2.411 2.411 2.42-2.42h.871l1.82-3.206z"
|
||||
/>
|
||||
<path
|
||||
data-name="Trazado 6844"
|
||||
d="M4.792 9.804L.267 14.329a.852.852 0 000 1.205l1.205 1.206a.853.853 0 001.206 0l4.524-4.525z"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
data-name="Trazado 6845"
|
||||
d="M16.415 14.325L6.679 4.59A3.381 3.381 0 002.527.437l2.069 2.067-2.411 2.411L.116 2.846a3.381 3.381 0 004.153 4.158l9.735 9.736a.853.853 0 001.206 0l1.205-1.206a.852.852 0 000-1.209z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</SvgIcon>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToolsIcon;
|
||||
@@ -102,3 +102,4 @@ export { default as UptimeIcon } from "./UptimeIcon";
|
||||
export { default as LambdaIcon } from "./LambdaIcon";
|
||||
export { default as TiersIcon } from "./TiersIcon";
|
||||
export { default as OpenListIcon } from "./OpenListIcon";
|
||||
export { default as ToolsIcon } from "./ToolsIcon";
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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 React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
@@ -22,13 +22,12 @@ import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import api from "../../../common/api";
|
||||
import { Button, IconButton, Tooltip } from "@mui/material";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
import { setErrorSnackMessage } from "../../../actions";
|
||||
import AddServiceAccount from "./AddServiceAccount";
|
||||
import DeleteServiceAccount from "./DeleteServiceAccount";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import { AddIcon, LockIcon } from "../../../icons";
|
||||
import { AccountIcon, AddIcon, LockIcon } from "../../../icons";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
@@ -42,6 +41,7 @@ import {
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import ChangePasswordModal from "./ChangePasswordModal";
|
||||
import SearchIcon from "../../../icons/SearchIcon";
|
||||
import HelpBox from "../../../common/HelpBox";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -75,6 +75,9 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
},
|
||||
},
|
||||
twHeight: {
|
||||
minHeight: 600,
|
||||
},
|
||||
imageIcon: {
|
||||
height: "100%",
|
||||
},
|
||||
@@ -212,7 +215,7 @@ const Account = ({
|
||||
closeModal={() => setChangePasswordModalOpen(false)}
|
||||
/>
|
||||
<PageHeader
|
||||
label="Account"
|
||||
label="Service Accounts"
|
||||
actions={
|
||||
<React.Fragment>
|
||||
{changePassword && (
|
||||
@@ -231,60 +234,79 @@ const Account = ({
|
||||
</React.Fragment>
|
||||
}
|
||||
/>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5" component="h5">
|
||||
Service Accounts
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Service Accounts"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setFilter(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
setSelectedServiceAccount(null);
|
||||
}}
|
||||
>
|
||||
Create service account
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName={"Service Accounts"}
|
||||
idField={""}
|
||||
columns={[{ label: "Service Account", elementKey: "" }]}
|
||||
itemActions={tableActions}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Service Accounts"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setFilter(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
setSelectedServiceAccount(null);
|
||||
}}
|
||||
>
|
||||
Create service account
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName={"Service Accounts"}
|
||||
idField={""}
|
||||
columns={[{ label: "Service Account", elementKey: "" }]}
|
||||
itemActions={tableActions}
|
||||
customPaperHeight={classes.twHeight}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<HelpBox
|
||||
title={"Learn more about SERVICE ACCOUNTS"}
|
||||
iconComponent={<AccountIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO service accounts are child identities of an authenticated
|
||||
MinIO user, including externally managed identities. Each
|
||||
service account inherits its privileges based on the policies
|
||||
attached to it’s parent user or those groups in which the parent
|
||||
user has membership. Service accounts also support an optional
|
||||
inline policy which further restricts access to a subset of
|
||||
actions and resources available to the parent user.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/security/minio-identity-management/user-management.html?ref=con#service-accounts"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -25,15 +25,14 @@ import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
import { Bucket, BucketList, HasPermissionResponse } from "../types";
|
||||
import {
|
||||
AddIcon,
|
||||
BucketsIcon,
|
||||
WatchIcon,
|
||||
} from "../../../../icons";
|
||||
import { AddIcon, BucketsIcon, WatchIcon } from "../../../../icons";
|
||||
import { AppState } from "../../../../store";
|
||||
import { addBucketOpen, addBucketReset } from "../actions";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import { containerForHeader, linkStyles } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
containerForHeader,
|
||||
linkStyles,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../../common/types";
|
||||
import api from "../../../../common/api";
|
||||
import AddBucket from "./AddBucket";
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IElement } from "../../Configurations/types";
|
||||
interface ISettingsCard {
|
||||
classes: any;
|
||||
configuration: IElement;
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -55,10 +56,14 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
});
|
||||
|
||||
const SettingsCard = ({ classes, configuration }: ISettingsCard) => {
|
||||
const SettingsCard = ({
|
||||
classes,
|
||||
configuration,
|
||||
prefix = "settings",
|
||||
}: ISettingsCard) => {
|
||||
return (
|
||||
<Link
|
||||
to={`/settings/${configuration.configuration_id}`}
|
||||
to={`/${prefix}/${configuration.configuration_id}`}
|
||||
className={classes.configurationLink}
|
||||
>
|
||||
{configuration.icon}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { AutoSizer } from "react-virtualized";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
|
||||
interface ISlideOptions {
|
||||
classes: any;
|
||||
slideOptions: any;
|
||||
currentSlide: number;
|
||||
}
|
||||
|
||||
const styles = () =>
|
||||
createStyles({
|
||||
masterContainer: {
|
||||
overflowX: "hidden",
|
||||
overflowY: "auto",
|
||||
},
|
||||
sliderContainer: {
|
||||
width: "auto",
|
||||
transitionDuration: "0.3s",
|
||||
position: "relative",
|
||||
},
|
||||
slide: {
|
||||
float: "left",
|
||||
},
|
||||
});
|
||||
|
||||
const SlideOptions = ({
|
||||
classes,
|
||||
slideOptions,
|
||||
currentSlide,
|
||||
}: ISlideOptions) => {
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }: any) => {
|
||||
const currentSliderPosition = currentSlide * width;
|
||||
const containerSize = width * slideOptions.length;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.masterContainer} style={{ width, height }}>
|
||||
<div
|
||||
className={classes.sliderContainer}
|
||||
style={{
|
||||
left: `-${currentSliderPosition}px`,
|
||||
width: `${containerSize}px`,
|
||||
}}
|
||||
>
|
||||
{slideOptions.map((block: any, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className={classes.slide}
|
||||
style={{ width }}
|
||||
key={`slide-panel-${index.toString()}`}
|
||||
>
|
||||
{block}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SlideOptions);
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from "react";
|
||||
import { IIcon, selected, unSelected } from "./common";
|
||||
|
||||
const DescriptionIcon = ({ active = false }: IIcon) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 10 11.429"
|
||||
>
|
||||
<path
|
||||
fill={active ? selected : unSelected}
|
||||
d="M-43.375,11.429-48.35,8.664l-5.025,2.764V0h10Z"
|
||||
transform="translate(53.375)"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default DescriptionIcon;
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import SettingsCard from "../../Common/SettingsCard/SettingsCard";
|
||||
import HelpBox from "../../../../common/HelpBox";
|
||||
import { SettingsIcon } from "../../../../icons";
|
||||
|
||||
interface IConfigurationOptions {
|
||||
classes: any;
|
||||
@@ -91,6 +93,29 @@ const ConfigurationOptions = ({ classes }: IConfigurationOptions) => {
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<HelpBox
|
||||
title={"Learn more about SETTINGS"}
|
||||
iconComponent={<SettingsIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO supports a variety of configurations ranging from
|
||||
encryption, compression, region, notifications, etc.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/reference/minio-cli/minio-mc-admin/mc-admin.config.html?ref=con#id4"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState, Fragment } from "react";
|
||||
import get from "lodash/get";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import history from "../../../../history";
|
||||
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
|
||||
import { configurationElements } from "../utils";
|
||||
import { IConfigurationElement } from "../types";
|
||||
import EditConfiguration from "../../NotificationEndpoints/CustomForms/EditConfiguration";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
settingsCommon,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import SlideOptions from "../../Common/SlideOptions/SlideOptions";
|
||||
import BackSettingsIcon from "../../../../icons/BackSettingsIcon";
|
||||
|
||||
interface IListConfiguration {
|
||||
classes: any;
|
||||
history: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
strongText: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
keyName: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
iconText: {
|
||||
lineHeight: "24px",
|
||||
},
|
||||
customConfigurationPage: {
|
||||
height: "calc(100vh - 324px)",
|
||||
scrollbarWidth: "none" as const,
|
||||
"&::-webkit-scrollbar": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
...searchField,
|
||||
...actionsTray,
|
||||
...settingsCommon,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const initialConfiguration = {
|
||||
configuration_id: "",
|
||||
configuration_label: "",
|
||||
};
|
||||
|
||||
const ConfigurationsList = ({ classes, history }: IListConfiguration) => {
|
||||
const [selectedConfiguration, setSelectedConfiguration] =
|
||||
useState(initialConfiguration);
|
||||
const [currentConfiguration, setCurrentConfiguration] = useState<number>(0);
|
||||
|
||||
const tableActions = [
|
||||
{
|
||||
type: "edit",
|
||||
onClick: (element: IConfigurationElement) => {
|
||||
const url = get(element, "url", "");
|
||||
if (url !== "") {
|
||||
// We redirect Browser
|
||||
history.push(url);
|
||||
} else {
|
||||
setCurrentConfiguration(1);
|
||||
setSelectedConfiguration(element);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const backToInitialConfig = () => {
|
||||
setCurrentConfiguration(0);
|
||||
setSelectedConfiguration(initialConfiguration);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.settingsOptionsContainer}>
|
||||
<SlideOptions
|
||||
slideOptions={[
|
||||
<Fragment>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{
|
||||
label: "Configuration",
|
||||
elementKey: "configuration_id",
|
||||
},
|
||||
]}
|
||||
isLoading={false}
|
||||
records={configurationElements}
|
||||
entityName="Configurations"
|
||||
idField="configuration_id"
|
||||
customPaperHeight={classes.customConfigurationPage}
|
||||
noBackground
|
||||
/>
|
||||
</Fragment>,
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.backContainer}>
|
||||
<button
|
||||
onClick={backToInitialConfig}
|
||||
className={classes.backButton}
|
||||
>
|
||||
<BackSettingsIcon />
|
||||
Back To Configurations
|
||||
</button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{currentConfiguration === 1 ? (
|
||||
<EditConfiguration
|
||||
history={history}
|
||||
selectedConfiguration={selectedConfiguration}
|
||||
/>
|
||||
) : null}
|
||||
</Grid>
|
||||
</Fragment>,
|
||||
]}
|
||||
currentSlide={currentConfiguration}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ConfigurationsList);
|
||||
@@ -20,7 +20,7 @@ import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IconButton, LinearProgress, TextField } from "@mui/material";
|
||||
import { LinearProgress, TextField } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Button from "@mui/material/Button";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
|
||||
@@ -47,7 +47,6 @@ import ConfigurationMain from "./Configurations/ConfigurationMain";
|
||||
import TenantDetails from "./Tenants/TenantDetails/TenantDetails";
|
||||
import License from "./License/License";
|
||||
import Trace from "./Trace/Trace";
|
||||
import LogsMain from "./Logs/LogsMain";
|
||||
import Heal from "./Heal/Heal";
|
||||
import Watch from "./Watch/Watch";
|
||||
import HealthInfo from "./HealthInfo/HealthInfo";
|
||||
@@ -63,6 +62,9 @@ import ListTiersConfiguration from "./Configurations/TiersConfiguration/ListTier
|
||||
import TierTypeSelector from "./Configurations/TiersConfiguration/TierTypeSelector";
|
||||
import AddTierConfiguration from "./Configurations/TiersConfiguration/AddTierConfiguration";
|
||||
import ListTenants from "./Tenants/ListTenants/ListTenants";
|
||||
import Tools from "./Tools/Tools";
|
||||
import ErrorLogs from "./Logs/ErrorLogs/ErrorLogs";
|
||||
import LogsSearchMain from "./Logs/LogSearch/LogsSearchMain";
|
||||
|
||||
const drawerWidth = 245;
|
||||
|
||||
@@ -243,7 +245,7 @@ const Console = ({
|
||||
},
|
||||
{
|
||||
component: Watch,
|
||||
path: "/watch",
|
||||
path: "/tools/watch",
|
||||
},
|
||||
{
|
||||
component: Users,
|
||||
@@ -267,19 +269,27 @@ const Console = ({
|
||||
},
|
||||
{
|
||||
component: Heal,
|
||||
path: "/heal",
|
||||
path: "/tools/heal",
|
||||
},
|
||||
{
|
||||
component: Trace,
|
||||
path: "/trace",
|
||||
},
|
||||
{
|
||||
component: LogsMain,
|
||||
path: "/logs",
|
||||
path: "/tools/trace",
|
||||
},
|
||||
{
|
||||
component: HealthInfo,
|
||||
path: "/health-info",
|
||||
path: "/tools/diagnostics",
|
||||
},
|
||||
{
|
||||
component: ErrorLogs,
|
||||
path: "/tools/logs",
|
||||
},
|
||||
{
|
||||
component: LogsSearchMain,
|
||||
path: "/tools/audit-logs",
|
||||
},
|
||||
{
|
||||
component: Tools,
|
||||
path: "/tools",
|
||||
},
|
||||
{
|
||||
component: ConfigurationMain,
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import React from "react";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import {
|
||||
LineChart,
|
||||
Line,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Label,
|
||||
ResponsiveContainer,
|
||||
} from "recharts";
|
||||
import Title from "../../../common/Title";
|
||||
|
||||
// Generate Sales Data
|
||||
function createData(time: string, amount: number) {
|
||||
return { time, amount };
|
||||
}
|
||||
|
||||
const data = [
|
||||
createData("00:00", 0),
|
||||
createData("03:00", 300),
|
||||
createData("06:00", 600),
|
||||
createData("09:00", 800),
|
||||
createData("12:00", 1500),
|
||||
createData("15:00", 2000),
|
||||
createData("18:00", 2400),
|
||||
createData("21:00", 2400),
|
||||
];
|
||||
|
||||
export default function Chart() {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title>Today</Title>
|
||||
<ResponsiveContainer width="99%">
|
||||
<LineChart
|
||||
data={data}
|
||||
margin={{
|
||||
top: 16,
|
||||
right: 16,
|
||||
bottom: 0,
|
||||
left: 24,
|
||||
}}
|
||||
>
|
||||
<XAxis dataKey="time" stroke={theme.palette.text.secondary} />
|
||||
<YAxis stroke={theme.palette.text.secondary}>
|
||||
<Label
|
||||
position="left"
|
||||
style={{ textAnchor: "middle", fill: theme.palette.text.primary }}
|
||||
>
|
||||
Sales ($)
|
||||
</Label>
|
||||
</YAxis>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="amount"
|
||||
stroke={theme.palette.primary.main}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import React from "react";
|
||||
import Link from "@mui/material/Link";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Title from "../../../common/Title";
|
||||
|
||||
function preventDefault(event: React.MouseEvent) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
const useStyles = makeStyles({
|
||||
depositContext: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
|
||||
export default function Deposits() {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title>Recent Deposits</Title>
|
||||
<Typography component="p" variant="h4">
|
||||
$3,024.00
|
||||
</Typography>
|
||||
<Typography color="textSecondary" className={classes.depositContext}>
|
||||
on 15 March, 2019
|
||||
</Typography>
|
||||
<div>
|
||||
<Link color="primary" href="#" onClick={preventDefault}>
|
||||
View balance
|
||||
</Link>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
import * as React from "react";
|
||||
import Link from "@mui/material/Link";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Title from "../../../common/Title";
|
||||
|
||||
// Generate Order Data
|
||||
function createData(
|
||||
id: number,
|
||||
date: string,
|
||||
name: string,
|
||||
shipTo: string,
|
||||
paymentMethod: string,
|
||||
amount: number
|
||||
) {
|
||||
return { id, date, name, shipTo, paymentMethod, amount };
|
||||
}
|
||||
|
||||
const rows = [
|
||||
createData(
|
||||
0,
|
||||
"16 Mar, 2019",
|
||||
"Elvis Presley",
|
||||
"Tupelo, MS",
|
||||
"VISA ⠀•••• 3719",
|
||||
312.44
|
||||
),
|
||||
createData(
|
||||
1,
|
||||
"16 Mar, 2019",
|
||||
"Paul McCartney",
|
||||
"London, UK",
|
||||
"VISA ⠀•••• 2574",
|
||||
866.99
|
||||
),
|
||||
createData(
|
||||
2,
|
||||
"16 Mar, 2019",
|
||||
"Tom Scholz",
|
||||
"Boston, MA",
|
||||
"MC ⠀•••• 1253",
|
||||
100.81
|
||||
),
|
||||
createData(
|
||||
3,
|
||||
"16 Mar, 2019",
|
||||
"Michael Jackson",
|
||||
"Gary, IN",
|
||||
"AMEX ⠀•••• 2000",
|
||||
654.39
|
||||
),
|
||||
createData(
|
||||
4,
|
||||
"15 Mar, 2019",
|
||||
"Bruce Springsteen",
|
||||
"Long Branch, NJ",
|
||||
"VISA ⠀•••• 5919",
|
||||
212.79
|
||||
),
|
||||
];
|
||||
|
||||
function preventDefault(event: React.MouseEvent) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
seeMore: {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
}));
|
||||
|
||||
export default function Orders() {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title>Recent Orders</Title>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>Name</TableCell>
|
||||
<TableCell>Ship To</TableCell>
|
||||
<TableCell>Payment Method</TableCell>
|
||||
<TableCell align="right">Sale Amount</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{rows.map((row) => (
|
||||
<TableRow key={row.id}>
|
||||
<TableCell>{row.date}</TableCell>
|
||||
<TableCell>{row.name}</TableCell>
|
||||
<TableCell>{row.shipTo}</TableCell>
|
||||
<TableCell>{row.paymentMethod}</TableCell>
|
||||
<TableCell align="right">{row.amount}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<div className={classes.seeMore}>
|
||||
<Link color="primary" href="#" onClick={preventDefault}>
|
||||
See more orders
|
||||
</Link>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -73,6 +73,9 @@ const styles = (theme: Theme) =>
|
||||
whiteSpace: "normal",
|
||||
wordWrap: "break-word",
|
||||
},
|
||||
twHeight: {
|
||||
minHeight: 600,
|
||||
},
|
||||
minTableHeader: {
|
||||
color: "#393939",
|
||||
"& tr": {
|
||||
@@ -241,6 +244,7 @@ const Groups = ({ classes, setErrorSnackMessage }: IGroupsProps) => {
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
customPaperHeight={classes.twHeight}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
|
||||
@@ -17,27 +17,35 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { HorizontalBar } from "react-chartjs-2";
|
||||
import { Button, Grid, TextField, InputBase } from "@mui/material";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Grid,
|
||||
InputBase,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import { FormControl, MenuItem, Select } from "@mui/material";
|
||||
import { BucketList, Bucket } from "../Watch/types";
|
||||
import { HealStatus, colorH } from "./types";
|
||||
import { Bucket, BucketList } from "../Watch/types";
|
||||
import { colorH, HealStatus } from "./types";
|
||||
import { niceBytes } from "../../../common/utils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
inlineCheckboxes,
|
||||
searchField,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { AppState } from "../../../store";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import CheckboxWrapper from "../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import api from "../../../common/api";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -242,123 +250,124 @@ const Heal = ({ classes, distributedSetup }: IHeal) => {
|
||||
<PageHeader label="Heal" />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<FormControl variant="outlined">
|
||||
<Select
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
value={bucketName}
|
||||
onChange={(e) => {
|
||||
setBucketName(e.target.value as string);
|
||||
}}
|
||||
className={classes.searchField}
|
||||
input={<SelectStyled />}
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="" key={`select-bucket-name-default`}>
|
||||
Select Bucket
|
||||
</MenuItem>
|
||||
{bucketNames.map((option) => (
|
||||
<MenuItem
|
||||
value={option.value}
|
||||
key={`select-bucket-name-${option.label}`}
|
||||
>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
placeholder="Prefix"
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<FormControl variant="outlined">
|
||||
<Select
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
value={bucketName}
|
||||
onChange={(e) => {
|
||||
setBucketName(e.target.value as string);
|
||||
}}
|
||||
className={classes.searchField}
|
||||
id="prefix-resource"
|
||||
label=""
|
||||
disabled={false}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={start}
|
||||
onClick={() => setStart(true)}
|
||||
input={<SelectStyled />}
|
||||
displayEmpty
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.inlineCheckboxes}>
|
||||
<CheckboxWrapper
|
||||
name="recursive"
|
||||
id="recursive"
|
||||
value="recursive"
|
||||
checked={recursive}
|
||||
onChange={(e) => {
|
||||
setRecursive(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Recursive"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStart"
|
||||
id="forceStart"
|
||||
value="forceStart"
|
||||
checked={forceStart}
|
||||
onChange={(e) => {
|
||||
setForceStart(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Start"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStop"
|
||||
id="forceStop"
|
||||
value="forceStop"
|
||||
checked={forceStop}
|
||||
onChange={(e) => {
|
||||
setForceStop(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Stop"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.graphContainer}>
|
||||
<HorizontalBar
|
||||
data={data}
|
||||
width={80}
|
||||
height={30}
|
||||
options={{
|
||||
title: {
|
||||
display: true,
|
||||
text: "Item's Health Status [%]",
|
||||
fontSize: 20,
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
position: "right",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Grid item xs={12} className={classes.scanInfo}>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Size scanned:</strong> {hStatus.sizeScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Objects healed:</strong> {hStatus.objectsHealed} /{" "}
|
||||
{hStatus.objectsScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Healing time:</strong> {hStatus.healDuration}s
|
||||
</div>
|
||||
</Grid>
|
||||
<MenuItem value="" key={`select-bucket-name-default`}>
|
||||
Select Bucket
|
||||
</MenuItem>
|
||||
{bucketNames.map((option) => (
|
||||
<MenuItem
|
||||
value={option.value}
|
||||
key={`select-bucket-name-${option.label}`}
|
||||
>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
placeholder="Prefix"
|
||||
className={classes.searchField}
|
||||
id="prefix-resource"
|
||||
label=""
|
||||
disabled={false}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={start}
|
||||
onClick={() => setStart(true)}
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.inlineCheckboxes}>
|
||||
<CheckboxWrapper
|
||||
name="recursive"
|
||||
id="recursive"
|
||||
value="recursive"
|
||||
checked={recursive}
|
||||
onChange={(e) => {
|
||||
setRecursive(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Recursive"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStart"
|
||||
id="forceStart"
|
||||
value="forceStart"
|
||||
checked={forceStart}
|
||||
onChange={(e) => {
|
||||
setForceStart(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Start"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStop"
|
||||
id="forceStop"
|
||||
value="forceStop"
|
||||
checked={forceStop}
|
||||
onChange={(e) => {
|
||||
setForceStop(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Stop"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.graphContainer}>
|
||||
<HorizontalBar
|
||||
data={data}
|
||||
width={80}
|
||||
height={30}
|
||||
options={{
|
||||
title: {
|
||||
display: true,
|
||||
text: "Item's Health Status [%]",
|
||||
fontSize: 20,
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
position: "right",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Grid item xs={12} className={classes.scanInfo}>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Size scanned:</strong> {hStatus.sizeScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Objects healed:</strong> {hStatus.objectsHealed} /{" "}
|
||||
{hStatus.objectsScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
<strong>Healing time:</strong> {hStatus.healDuration}s
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -13,38 +13,39 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
ICloseEvent,
|
||||
IMessageEvent,
|
||||
w3cwebsocket as W3CWebSocket,
|
||||
ICloseEvent,
|
||||
} from "websocket";
|
||||
import { AppState } from "../../../store";
|
||||
import { connect } from "react-redux";
|
||||
import { healthInfoMessageReceived, healthInfoResetMessage } from "./actions";
|
||||
import {
|
||||
HealthInfoMessage,
|
||||
DiagStatError,
|
||||
DiagStatInProgress,
|
||||
DiagStatSuccess,
|
||||
DiagStatError,
|
||||
HealthInfoMessage,
|
||||
} from "./types";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
wsProtocol,
|
||||
WSCloseAbnormalClosure,
|
||||
WSCloseInternalServerErr,
|
||||
WSClosePolicyViolation,
|
||||
WSCloseAbnormalClosure,
|
||||
wsProtocol,
|
||||
} from "../../../utils/wsUtils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { Grid, Button } from "@mui/material";
|
||||
import { Button, Grid } from "@mui/material";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import { setSnackBarMessage, setServerDiagStat } from "../../../actions";
|
||||
import { setServerDiagStat, setSnackBarMessage } from "../../../actions";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -66,6 +67,12 @@ const styles = (theme: Theme) =>
|
||||
justifyContent: "flex-start",
|
||||
gap: 20,
|
||||
},
|
||||
boxy: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 40,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
...actionsTray,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
@@ -200,8 +207,11 @@ const HealthInfo = ({
|
||||
<React.Fragment>
|
||||
<PageHeader label="Diagnostic" />
|
||||
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.boxy}>
|
||||
<Grid container className={classes.buttons}>
|
||||
<Grid key="start-diag" item>
|
||||
<Button
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React, { Fragment, useState, useEffect } from "react";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
@@ -30,10 +30,13 @@ import { timeFromDate } from "../../../../common/utils";
|
||||
import { wsProtocol } from "../../../../utils/wsUtils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
logsCommon,
|
||||
searchField,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import SearchIcon from "../../../../icons/SearchIcon";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -68,6 +71,7 @@ const styles = (theme: Theme) =>
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
...logsCommon,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
interface ILogs {
|
||||
@@ -325,32 +329,40 @@ const ErrorLogs = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid container className={classes.logsSubContainer}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Highlight Line"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setHighlight(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<PageHeader label="Logs" />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.logList}>{renderLines}</div>
|
||||
<Grid container className={classes.logsSubContainer}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Highlight Line"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setHighlight(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.logList}>{renderLines}</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState, useEffect, useCallback } from "react";
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import get from "lodash/get";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
@@ -40,6 +40,8 @@ import FilterInputWrapper from "../../Common/FormComponents/FilterInputWrapper/F
|
||||
import LogSearchFullModal from "./LogSearchFullModal";
|
||||
import { LogSearchColumnLabels } from "./utils";
|
||||
import DateRangeSelector from "../../Common/FormComponents/DateRangeSelector/DateRangeSelector";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
|
||||
interface ILogSearchProps {
|
||||
classes: any;
|
||||
@@ -285,187 +287,199 @@ const LogsSearchMain = ({
|
||||
onClose={closeViewExtraInformation}
|
||||
/>
|
||||
)}
|
||||
<Grid container className={classes.logsSubContainer}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.actionsTray} ${classes.timeContainers}`}
|
||||
>
|
||||
<DateRangeSelector
|
||||
setTimeEnd={setTimeEnd}
|
||||
setTimeStart={setTimeStart}
|
||||
timeEnd={timeEnd}
|
||||
timeStart={timeStart}
|
||||
/>
|
||||
|
||||
<PageHeader label="Audit Logs" />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={`${classes.advancedLabelContainer}`}>
|
||||
<div
|
||||
className={`${classes.blockCollapsed} ${
|
||||
filterOpen ? classes.filterOpen : ""
|
||||
}`}
|
||||
<Grid container className={classes.logsSubContainer}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.actionsTray} ${classes.timeContainers}`}
|
||||
>
|
||||
<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={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"
|
||||
/>
|
||||
<DateRangeSelector
|
||||
setTimeEnd={setTimeEnd}
|
||||
setTimeStart={setTimeStart}
|
||||
timeEnd={timeEnd}
|
||||
timeStart={timeStart}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={`${classes.advancedLabelContainer}`}>
|
||||
<div
|
||||
className={`${classes.blockCollapsed} ${
|
||||
filterOpen ? classes.filterOpen : ""
|
||||
}`}
|
||||
>
|
||||
<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={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>
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.actionsTray} ${classes.endLineAction}`}
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className={`${classes.advancedLabel} overrideMargin`}
|
||||
onClick={() => {
|
||||
setFilterOpen(!filterOpen);
|
||||
}}
|
||||
>
|
||||
Advanced Filters{" "}
|
||||
{filterOpen ? <ArrowDropUp /> : <ArrowDropDownIcon />}
|
||||
</button>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={triggerLoad}
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={`${classes.actionsTray} ${classes.endLineAction}`}
|
||||
>
|
||||
Get Information
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
columns={[
|
||||
{
|
||||
label: LogSearchColumnLabels.time,
|
||||
elementKey: "time",
|
||||
enableSort: true,
|
||||
},
|
||||
{ label: LogSearchColumnLabels.api_name, elementKey: "api_name" },
|
||||
{ label: LogSearchColumnLabels.bucket, elementKey: "bucket" },
|
||||
{ label: LogSearchColumnLabels.object, elementKey: "object" },
|
||||
{
|
||||
label: LogSearchColumnLabels.remote_host,
|
||||
elementKey: "remote_host",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.request_id,
|
||||
elementKey: "request_id",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.user_agent,
|
||||
elementKey: "user_agent",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.response_status,
|
||||
elementKey: "response_status",
|
||||
renderFunction: (element) => (
|
||||
<Fragment>
|
||||
<span>
|
||||
{element.response_status_code} ({element.response_status})
|
||||
</span>
|
||||
</Fragment>
|
||||
),
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.request_content_length,
|
||||
elementKey: "request_content_length",
|
||||
renderFunction: niceBytes,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.response_content_length,
|
||||
elementKey: "response_content_length",
|
||||
renderFunction: niceBytes,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.time_to_response_ns,
|
||||
elementKey: "time_to_response_ns",
|
||||
renderFunction: nsToSeconds,
|
||||
contentTextAlign: "right",
|
||||
},
|
||||
]}
|
||||
isLoading={loading}
|
||||
records={records}
|
||||
entityName="Logs"
|
||||
customEmptyMessage={"There is no information with this criteria"}
|
||||
idField="request_id"
|
||||
columnsSelector
|
||||
columnsShown={columnsShown}
|
||||
onColumnChange={selectColumn}
|
||||
customPaperHeight={
|
||||
filterOpen ? classes.tableFOpen : classes.tableFClosed
|
||||
}
|
||||
sortConfig={{
|
||||
currentSort: "time",
|
||||
currentDirection: sortOrder,
|
||||
triggerSort: sortChange,
|
||||
}}
|
||||
infiniteScrollConfig={{
|
||||
recordsCount: 1000000,
|
||||
loadMoreRecords: loadMoreRecords,
|
||||
}}
|
||||
itemActions={[
|
||||
{
|
||||
type: "view",
|
||||
onClick: openExtraInformation,
|
||||
},
|
||||
]}
|
||||
textSelectable
|
||||
/>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className={`${classes.advancedLabel} overrideMargin`}
|
||||
onClick={() => {
|
||||
setFilterOpen(!filterOpen);
|
||||
}}
|
||||
>
|
||||
Advanced Filters{" "}
|
||||
{filterOpen ? <ArrowDropUp /> : <ArrowDropDownIcon />}
|
||||
</button>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={triggerLoad}
|
||||
>
|
||||
Get Information
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
columns={[
|
||||
{
|
||||
label: LogSearchColumnLabels.time,
|
||||
elementKey: "time",
|
||||
enableSort: true,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.api_name,
|
||||
elementKey: "api_name",
|
||||
},
|
||||
{ label: LogSearchColumnLabels.bucket, elementKey: "bucket" },
|
||||
{ label: LogSearchColumnLabels.object, elementKey: "object" },
|
||||
{
|
||||
label: LogSearchColumnLabels.remote_host,
|
||||
elementKey: "remote_host",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.request_id,
|
||||
elementKey: "request_id",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.user_agent,
|
||||
elementKey: "user_agent",
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.response_status,
|
||||
elementKey: "response_status",
|
||||
renderFunction: (element) => (
|
||||
<Fragment>
|
||||
<span>
|
||||
{element.response_status_code} (
|
||||
{element.response_status})
|
||||
</span>
|
||||
</Fragment>
|
||||
),
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.request_content_length,
|
||||
elementKey: "request_content_length",
|
||||
renderFunction: niceBytes,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.response_content_length,
|
||||
elementKey: "response_content_length",
|
||||
renderFunction: niceBytes,
|
||||
},
|
||||
{
|
||||
label: LogSearchColumnLabels.time_to_response_ns,
|
||||
elementKey: "time_to_response_ns",
|
||||
renderFunction: nsToSeconds,
|
||||
contentTextAlign: "right",
|
||||
},
|
||||
]}
|
||||
isLoading={loading}
|
||||
records={records}
|
||||
entityName="Logs"
|
||||
customEmptyMessage={"There is no information with this criteria"}
|
||||
idField="request_id"
|
||||
columnsSelector
|
||||
columnsShown={columnsShown}
|
||||
onColumnChange={selectColumn}
|
||||
customPaperHeight={
|
||||
filterOpen ? classes.tableFOpen : classes.tableFClosed
|
||||
}
|
||||
sortConfig={{
|
||||
currentSort: "time",
|
||||
currentDirection: sortOrder,
|
||||
triggerSort: sortChange,
|
||||
}}
|
||||
infiniteScrollConfig={{
|
||||
recordsCount: 1000000,
|
||||
loadMoreRecords: loadMoreRecords,
|
||||
}}
|
||||
itemActions={[
|
||||
{
|
||||
type: "view",
|
||||
onClick: openExtraInformation,
|
||||
},
|
||||
]}
|
||||
textSelectable
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import { Grid, List, ListItem, ListItemText } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { containerForHeader } from "../Common/FormComponents/common/styleLibrary";
|
||||
import ErrorLogs from "./ErrorLogs/ErrorLogs";
|
||||
import LogsSearchMain from "./LogSearch/LogsSearchMain";
|
||||
import { AppState } from "../../../store";
|
||||
|
||||
interface ILogsMainProps {
|
||||
classes: any;
|
||||
features: string[] | null;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
headerLabel: {
|
||||
fontSize: 22,
|
||||
fontWeight: 600,
|
||||
color: "#000",
|
||||
marginTop: 4,
|
||||
},
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const LogsMain = ({ classes, features }: ILogsMainProps) => {
|
||||
const [currentTab, setCurrentTab] = useState<number>(0);
|
||||
|
||||
const logSearchEnabled = features && features.includes("log-search");
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label="Logs" />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={2}>
|
||||
<List component="nav" dense={true}>
|
||||
<ListItem
|
||||
button
|
||||
selected={currentTab === 0}
|
||||
onClick={() => {
|
||||
setCurrentTab(0);
|
||||
}}
|
||||
>
|
||||
<ListItemText primary="Error Logs" />
|
||||
</ListItem>
|
||||
<ListItem
|
||||
button
|
||||
selected={currentTab === 1}
|
||||
disabled={!logSearchEnabled}
|
||||
onClick={() => {
|
||||
setCurrentTab(1);
|
||||
}}
|
||||
>
|
||||
<ListItemText primary="Audit Logs" />
|
||||
</ListItem>
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
{currentTab === 0 && (
|
||||
<Fragment>
|
||||
<h1 className={classes.sectionTitle}>Error Logs</h1>
|
||||
<ErrorLogs />
|
||||
</Fragment>
|
||||
)}
|
||||
{currentTab === 1 && logSearchEnabled && (
|
||||
<Fragment>
|
||||
<h1 className={classes.sectionTitle}>Audit Logs</h1>
|
||||
<LogsSearchMain />
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
features: state.console.session.features,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
export default withStyles(styles)(connector(LogsMain));
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
IAMPoliciesIcon,
|
||||
LambdaIcon,
|
||||
TiersIcon,
|
||||
TraceIcon,
|
||||
ToolsIcon,
|
||||
UsersIcon,
|
||||
VersionIcon,
|
||||
} from "../../../icons";
|
||||
@@ -45,15 +45,12 @@ import { clearSession } from "../../../common/utils";
|
||||
import LicenseIcon from "../../../icons/LicenseIcon";
|
||||
import LogoutIcon from "../../../icons/LogoutIcon";
|
||||
import HealIcon from "../../../icons/HealIcon";
|
||||
import WatchIcon from "../../../icons/WatchIcon";
|
||||
import OperatorLogo from "../../../icons/OperatorLogo";
|
||||
import ConsoleLogo from "../../../icons/ConsoleLogo";
|
||||
import history from "../../../history";
|
||||
import api from "../../../common/api";
|
||||
import AccountIcon from "../../../icons/AccountIcon";
|
||||
import DiagnosticsIcon from "../../../icons/DiagnosticsIcon";
|
||||
import DocumentationIcon from "../../../icons/DocumentationIcon";
|
||||
import LogsIcon from "../../../icons/LogsIcon";
|
||||
import SettingsIcon from "../../../icons/SettingsIcon";
|
||||
import StorageIcon from "../../../icons/StorageIcon";
|
||||
import TenantsOutlinedIcon from "../../../icons/TenantsOutlineIcon";
|
||||
@@ -383,28 +380,12 @@ const Menu = ({
|
||||
icon: <TiersIcon />,
|
||||
},
|
||||
{
|
||||
group: "Tools",
|
||||
group: "common",
|
||||
type: "item",
|
||||
component: NavLink,
|
||||
to: "/logs",
|
||||
name: "Logs",
|
||||
icon: <LogsIcon />,
|
||||
},
|
||||
{
|
||||
group: "Tools",
|
||||
type: "item",
|
||||
component: NavLink,
|
||||
to: "/watch",
|
||||
name: "Watch",
|
||||
icon: <WatchIcon />,
|
||||
},
|
||||
{
|
||||
group: "Tools",
|
||||
type: "item",
|
||||
component: NavLink,
|
||||
to: "/trace",
|
||||
name: "Trace",
|
||||
icon: <TraceIcon />,
|
||||
to: "/tools",
|
||||
name: "Tools",
|
||||
icon: <ToolsIcon />,
|
||||
},
|
||||
{
|
||||
group: "Tools",
|
||||
@@ -415,14 +396,6 @@ const Menu = ({
|
||||
icon: <HealIcon />,
|
||||
fsHidden: distributedSetup,
|
||||
},
|
||||
{
|
||||
group: "Tools",
|
||||
type: "item",
|
||||
component: NavLink,
|
||||
to: "/health-info",
|
||||
name: "Diagnostic",
|
||||
icon: <DiagnosticsIcon />,
|
||||
},
|
||||
|
||||
{
|
||||
group: "Operator",
|
||||
|
||||
@@ -19,7 +19,7 @@ import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { IconButton, LinearProgress, TextField } from "@mui/material";
|
||||
import { LinearProgress, TextField } from "@mui/material";
|
||||
import { red } from "@mui/material/colors";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord";
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import get from "lodash/get";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
@@ -25,7 +25,7 @@ import Grid from "@mui/material/Grid";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import { Policy, PolicyList } from "./types";
|
||||
import { AddIcon } from "../../../icons";
|
||||
import { AddIcon, IAMPoliciesIcon } from "../../../icons";
|
||||
import { setErrorSnackMessage } from "../../../actions";
|
||||
import {
|
||||
actionsTray,
|
||||
@@ -40,6 +40,7 @@ import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import api from "../../../common/api";
|
||||
import history from "../../../history";
|
||||
import SearchIcon from "../../../icons/SearchIcon";
|
||||
import HelpBox from "../../../common/HelpBox";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -68,6 +69,9 @@ const styles = (theme: Theme) =>
|
||||
},
|
||||
},
|
||||
},
|
||||
twHeight: {
|
||||
minHeight: 600,
|
||||
},
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
@@ -175,52 +179,84 @@ const ListPolicies = ({ classes, setErrorSnackMessage }: IPoliciesProps) => {
|
||||
/>
|
||||
)}
|
||||
<PageHeader label="IAM Policies" />
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Policies"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setFilterPolicies(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
setPolicyEdit(null);
|
||||
}}
|
||||
>
|
||||
Create Policy
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "name" }]}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Policies"
|
||||
idField="name"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Search Policies"
|
||||
className={classes.searchField}
|
||||
id="search-resource"
|
||||
label=""
|
||||
onChange={(val) => {
|
||||
setFilterPolicies(val.target.value);
|
||||
}}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => {
|
||||
setAddScreenOpen(true);
|
||||
setPolicyEdit(null);
|
||||
}}
|
||||
>
|
||||
Create Policy
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "name" }]}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Policies"
|
||||
idField="name"
|
||||
customPaperHeight={classes.twHeight}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<HelpBox
|
||||
title={"Learn more about IAM POLICIES"}
|
||||
iconComponent={<IAMPoliciesIcon />}
|
||||
help={
|
||||
<Fragment>
|
||||
MinIO uses Policy-Based Access Control (PBAC) to define the
|
||||
authorized actions and resources to which an authenticated user
|
||||
has access. Each policy describes one or more actions and
|
||||
conditions that outline the permissions of a user or group of
|
||||
users.
|
||||
<br />
|
||||
<br />
|
||||
MinIO PBAC is built for compatibility with AWS IAM policy
|
||||
syntax, structure, and behavior. The MinIO documentation makes a
|
||||
best-effort to cover IAM-specific behavior and functionality.
|
||||
Consider deferring to the IAM documentation for more complete
|
||||
documentation on AWS IAM-specific topics.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
<a
|
||||
href="https://docs.min.io/minio/baremetal/security/minio-identity-management/policy-based-access-control.html?ref=con"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
documentation
|
||||
</a>
|
||||
.
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import { AppState } from "../../../../../store";
|
||||
import {
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import { Paper } from "@mui/material";
|
||||
|
||||
interface IPreviewProps {
|
||||
classes: any;
|
||||
tenantName: string;
|
||||
customImage: boolean;
|
||||
imageName: string;
|
||||
namespace: string;
|
||||
selectedStorageClass: string;
|
||||
volumeSize: string;
|
||||
sizeFactor: string;
|
||||
advancedMode: boolean;
|
||||
enableTLS: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalBasic,
|
||||
...wizardCommon,
|
||||
});
|
||||
|
||||
const Preview = ({
|
||||
classes,
|
||||
tenantName,
|
||||
customImage,
|
||||
imageName,
|
||||
namespace,
|
||||
selectedStorageClass,
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
advancedMode,
|
||||
enableTLS,
|
||||
}: IPreviewProps) => {
|
||||
return (
|
||||
<Paper className={classes.paperWrapper}>
|
||||
<div className={classes.headerElement}>
|
||||
<h3 className={classes.h3Section}>Review</h3>
|
||||
<span className={classes.descriptionText}>
|
||||
Review the details of the new tenant
|
||||
</span>
|
||||
</div>
|
||||
<Table size="small">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
Tenant Name
|
||||
</TableCell>
|
||||
<TableCell>{tenantName}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{customImage && (
|
||||
<Fragment>
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
MinIO Image
|
||||
</TableCell>
|
||||
<TableCell>{imageName}</TableCell>
|
||||
</TableRow>
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{namespace !== "" && (
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
Namespace
|
||||
</TableCell>
|
||||
<TableCell>{namespace}</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
Storage Class
|
||||
</TableCell>
|
||||
<TableCell>{selectedStorageClass}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
Total Size
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{volumeSize} {sizeFactor}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{advancedMode && (
|
||||
<Fragment>
|
||||
<TableRow>
|
||||
<TableCell align="right" className={classes.tableTitle}>
|
||||
Enable TLS
|
||||
</TableCell>
|
||||
<TableCell>{enableTLS ? "Enabled" : "Disabled"}</TableCell>
|
||||
</TableRow>
|
||||
</Fragment>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
advancedMode: state.tenants.createTenant.advancedModeOn,
|
||||
enableTLS: state.tenants.createTenant.fields.security.enableTLS,
|
||||
tenantName: state.tenants.createTenant.fields.nameTenant.tenantName,
|
||||
selectedStorageClass:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageClass,
|
||||
customImage: state.tenants.createTenant.fields.configure.customImage,
|
||||
imageName: state.tenants.createTenant.fields.configure.imageName,
|
||||
namespace: state.tenants.createTenant.fields.nameTenant.namespace,
|
||||
volumeSize: state.tenants.createTenant.fields.tenantSize.volumeSize,
|
||||
sizeFactor: state.tenants.createTenant.fields.tenantSize.sizeFactor,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, {});
|
||||
|
||||
export default withStyles(styles)(connector(Preview));
|
||||
@@ -19,7 +19,7 @@ import { connect } from "react-redux";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import { Box, Button, IconButton, LinearProgress } from "@mui/material";
|
||||
import { Box, Button, LinearProgress } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React, { useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { modalBasic } from "../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import { Button, LinearProgress, SelectChangeEvent } from "@mui/material";
|
||||
import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
|
||||
interface IReplicationProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
closeModalAndRefresh: (refreshList: boolean) => void;
|
||||
}
|
||||
|
||||
interface IDropDownElements {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
multiContainer: {
|
||||
display: "flex",
|
||||
alignItems: "center" as const,
|
||||
justifyContent: "flex-start" as const,
|
||||
},
|
||||
sizeFactorContainer: {
|
||||
marginLeft: 8,
|
||||
},
|
||||
...modalBasic,
|
||||
});
|
||||
|
||||
const ReplicationSetup = ({
|
||||
classes,
|
||||
open,
|
||||
closeModalAndRefresh,
|
||||
}: IReplicationProps) => {
|
||||
const [addSending, setAddSending] = useState<boolean>(false);
|
||||
const [selectedTab, setSelectedTab] = useState<number>(0);
|
||||
const [sourceBucket, setSourceBucket] = useState<string>("");
|
||||
const [clusterSelected, setClusterSelected] = useState<string>("");
|
||||
const [destinationBucket, setDestinationBucket] = useState<string>("");
|
||||
const [address, setAddress] = useState<string>("");
|
||||
const [bucket, setBucket] = useState<string>("");
|
||||
const [accessKey, setAccessKey] = useState<string>("");
|
||||
const [secretKey, setSecretKey] = useState<string>("");
|
||||
|
||||
const clustersList: IDropDownElements[] = [];
|
||||
const sourceBuckets: IDropDownElements[] = [];
|
||||
const destinationBuckets: IDropDownElements[] = [];
|
||||
|
||||
return (
|
||||
<ModalWrapper
|
||||
modalOpen={open}
|
||||
title="Add Pool"
|
||||
onClose={() => {
|
||||
closeModalAndRefresh(false);
|
||||
}}
|
||||
>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setAddSending(true);
|
||||
}}
|
||||
>
|
||||
<Grid item xs={12}>
|
||||
<SelectWrapper
|
||||
label="Source Bucket"
|
||||
options={sourceBuckets}
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
setSourceBucket(e.target.value as string);
|
||||
}}
|
||||
value={sourceBucket}
|
||||
name="source_bucket"
|
||||
id="source_bucket"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Tabs
|
||||
value={selectedTab}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
onChange={(_, newValue: number) => {
|
||||
setSelectedTab(newValue);
|
||||
}}
|
||||
aria-label="cluster-tabs"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
>
|
||||
<Tab label="Local Cluster" />
|
||||
<Tab label="Remote Cluster" />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
{selectedTab === 0 && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<SelectWrapper
|
||||
label="Cluster"
|
||||
options={clustersList}
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
setClusterSelected(e.target.value as string);
|
||||
}}
|
||||
value={clusterSelected}
|
||||
name="cluster"
|
||||
id="cluster"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<SelectWrapper
|
||||
label="Destination Bucket"
|
||||
options={destinationBuckets}
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
setDestinationBucket(e.target.value as string);
|
||||
}}
|
||||
value={destinationBucket}
|
||||
name="destination_bucket"
|
||||
id="destination_bucket"
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{selectedTab === 1 && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="address"
|
||||
name="address"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setAddress(e.target.value);
|
||||
}}
|
||||
label="Address"
|
||||
value={address}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="bucket"
|
||||
name="bucket"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setBucket(e.target.value);
|
||||
}}
|
||||
label="Bucket"
|
||||
value={bucket}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="accessKey"
|
||||
name="accessKey"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setAccessKey(e.target.value);
|
||||
}}
|
||||
label="Access Key"
|
||||
value={accessKey}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="secretKey"
|
||||
name="secretKey"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSecretKey(e.target.value);
|
||||
}}
|
||||
label="Secret Key"
|
||||
value={secretKey}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={addSending}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</Grid>
|
||||
{addSending && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ReplicationSetup);
|
||||
@@ -14,7 +14,21 @@
|
||||
// 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/>.
|
||||
|
||||
export interface ServiceAccountsList {
|
||||
service_accounts: string[];
|
||||
total: number;
|
||||
}
|
||||
import React from "react";
|
||||
import { Route, Router, Switch } from "react-router-dom";
|
||||
import history from "../../../history";
|
||||
import NotFoundPage from "../../NotFoundPage";
|
||||
import ToolsList from "./ToolsPanel/ToolsList";
|
||||
|
||||
const Tools = () => {
|
||||
return (
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path="/tools" exact component={ToolsList} />
|
||||
<Route component={NotFoundPage} />
|
||||
</Switch>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tools;
|
||||
100
portal-ui/src/screens/Console/Tools/ToolsPanel/ToolsList.tsx
Normal file
100
portal-ui/src/screens/Console/Tools/ToolsPanel/ToolsList.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
import { configurationElements } from "../utils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
} from "../../Common/FormComponents/common/styleLibrary";
|
||||
import PageHeader from "../../Common/PageHeader/PageHeader";
|
||||
import SettingsCard from "../../Common/SettingsCard/SettingsCard";
|
||||
|
||||
interface IConfigurationOptions {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
strongText: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
keyName: {
|
||||
marginLeft: 5,
|
||||
},
|
||||
iconText: {
|
||||
lineHeight: "24px",
|
||||
},
|
||||
customConfigurationPage: {
|
||||
height: "calc(100vh - 324px)",
|
||||
scrollbarWidth: "none" as const,
|
||||
"&::-webkit-scrollbar": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
settingsOptionsContainer: {
|
||||
display: "flex" as const,
|
||||
flexDirection: "row" as const,
|
||||
justifyContent: "flex-start" as const,
|
||||
flexWrap: "wrap" as const,
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 5,
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
configurationLink: {
|
||||
border: "#E5E5E5 1px solid",
|
||||
borderRadius: 2,
|
||||
padding: 20,
|
||||
width: 190,
|
||||
height: 80,
|
||||
margin: 15,
|
||||
},
|
||||
...searchField,
|
||||
...actionsTray,
|
||||
...containerForHeader(theme.spacing(4)),
|
||||
});
|
||||
|
||||
const ToolsList = ({ classes }: IConfigurationOptions) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label={"Tools"} />
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.settingsOptionsContainer}>
|
||||
{configurationElements.map((element) => (
|
||||
<SettingsCard
|
||||
prefix={"tools"}
|
||||
configuration={element}
|
||||
key={`configItem-${element.configuration_label}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ToolsList);
|
||||
61
portal-ui/src/screens/Console/Tools/types.ts
Normal file
61
portal-ui/src/screens/Console/Tools/types.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { SelectorTypes } from "../Common/FormComponents/RadioGroupSelector/RadioGroupSelector";
|
||||
|
||||
export type KVFieldType =
|
||||
| "string"
|
||||
| "number"
|
||||
| "on|off"
|
||||
| "enum"
|
||||
| "path"
|
||||
| "url"
|
||||
| "address"
|
||||
| "duration"
|
||||
| "uri"
|
||||
| "sentence"
|
||||
| "csv"
|
||||
| "comment"
|
||||
| "switch";
|
||||
|
||||
export interface KVField {
|
||||
name: string;
|
||||
label: string;
|
||||
tooltip: string;
|
||||
required?: boolean;
|
||||
type: KVFieldType;
|
||||
options?: SelectorTypes[];
|
||||
multiline?: boolean;
|
||||
placeholder?: string;
|
||||
withBorder?: boolean;
|
||||
}
|
||||
|
||||
export interface IConfigurationElement {
|
||||
configuration_id: string;
|
||||
configuration_label: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface IElementValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IElement {
|
||||
configuration_id: string;
|
||||
configuration_label: string;
|
||||
icon?: any;
|
||||
}
|
||||
58
portal-ui/src/screens/Console/Tools/utils.tsx
Normal file
58
portal-ui/src/screens/Console/Tools/utils.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
import { IElement } from "./types";
|
||||
import {
|
||||
DiagnosticsIcon,
|
||||
HealIcon,
|
||||
LogsIcon,
|
||||
SearchIcon,
|
||||
TraceIcon,
|
||||
WatchIcon,
|
||||
} from "../../../icons";
|
||||
|
||||
export const configurationElements: IElement[] = [
|
||||
{
|
||||
icon: <LogsIcon />,
|
||||
configuration_id: "logs",
|
||||
configuration_label: "Logs",
|
||||
},
|
||||
{
|
||||
icon: <SearchIcon />,
|
||||
configuration_id: "audit-logs",
|
||||
configuration_label: "Audit Logs",
|
||||
},
|
||||
{
|
||||
icon: <WatchIcon />,
|
||||
configuration_id: "watch",
|
||||
configuration_label: "Watch",
|
||||
},
|
||||
{
|
||||
icon: <TraceIcon />,
|
||||
configuration_id: "trace",
|
||||
configuration_label: "trace",
|
||||
},
|
||||
{
|
||||
icon: <HealIcon />,
|
||||
configuration_id: "heal",
|
||||
configuration_label: "heal",
|
||||
},
|
||||
{
|
||||
icon: <DiagnosticsIcon />,
|
||||
configuration_id: "diagnostics",
|
||||
configuration_label: "Diagnostics",
|
||||
},
|
||||
];
|
||||
@@ -14,15 +14,15 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState, Fragment } from "react";
|
||||
import { Grid, Button, TextField } from "@mui/material";
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { Button, Grid, TextField } from "@mui/material";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { AppState } from "../../../store";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
setTraceStarted,
|
||||
traceMessageReceived,
|
||||
traceResetMessages,
|
||||
setTraceStarted,
|
||||
} from "./actions";
|
||||
import { TraceMessage } from "./types";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
@@ -31,16 +31,17 @@ import withStyles from "@mui/styles/withStyles";
|
||||
import { niceBytes, timeFromDate } from "../../../common/utils";
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import {
|
||||
containerForHeader,
|
||||
searchField,
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
hrClass,
|
||||
inlineCheckboxes,
|
||||
searchField,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import CheckboxWrapper from "../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
|
||||
import moment from "moment/moment";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -192,246 +193,247 @@ const Trace = ({
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader label={"Trace"} />
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Status Code"
|
||||
className={classes.searchField}
|
||||
id="status-code"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={statusCode}
|
||||
onChange={(e) => {
|
||||
setStatusCode(e.target.value);
|
||||
}}
|
||||
disabled={traceStarted}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Method"
|
||||
className={classes.searchField}
|
||||
id="method"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={method}
|
||||
onChange={(e) => {
|
||||
setMethod(e.target.value);
|
||||
}}
|
||||
disabled={traceStarted}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Function Name"
|
||||
className={classes.searchField}
|
||||
id="func-name"
|
||||
label=""
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={func}
|
||||
onChange={(e) => {
|
||||
setFunc(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Path"
|
||||
className={classes.searchField}
|
||||
id="path"
|
||||
label=""
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={path}
|
||||
onChange={(e) => {
|
||||
setPath(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
type="number"
|
||||
className={classes.searchField}
|
||||
id="fthreshold"
|
||||
label="Response Threshold"
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
inputProps={{
|
||||
min: 0,
|
||||
}}
|
||||
value={threshold}
|
||||
onChange={(e) => {
|
||||
setThreshold(parseInt(e.target.value));
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.inlineCheckboxes}>
|
||||
<span className={classes.labelCheckboxes}>Calls to trace:</span>
|
||||
<CheckboxWrapper
|
||||
checked={all}
|
||||
id={"all_calls"}
|
||||
name={"all_calls"}
|
||||
label={"All"}
|
||||
onChange={(item) => {
|
||||
setAll(item.target.checked);
|
||||
}}
|
||||
value={"all"}
|
||||
disabled={traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={s3 || all}
|
||||
id={"s3_calls"}
|
||||
name={"s3_calls"}
|
||||
label={"S3"}
|
||||
onChange={(item) => {
|
||||
setS3(item.target.checked);
|
||||
}}
|
||||
value={"s3"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={internal || all}
|
||||
id={"internal_calls"}
|
||||
name={"internal_calls"}
|
||||
label={"Internal"}
|
||||
onChange={(item) => {
|
||||
setInternal(item.target.checked);
|
||||
}}
|
||||
value={"internal"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={storage || all}
|
||||
id={"storage_calls"}
|
||||
name={"storage_calls"}
|
||||
label={"Storage"}
|
||||
onChange={(item) => {
|
||||
setStorage(item.target.checked);
|
||||
}}
|
||||
value={"storage"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={os || all}
|
||||
id={"os_calls"}
|
||||
name={"os_calls"}
|
||||
label={"OS"}
|
||||
onChange={(item) => {
|
||||
setOS(item.target.checked);
|
||||
}}
|
||||
value={"os"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<span className={classes.labelCheckboxes}>
|
||||
|
|
||||
</span>
|
||||
<CheckboxWrapper
|
||||
checked={errors}
|
||||
id={"only_errors"}
|
||||
name={"only_errors"}
|
||||
label={"Display only Errors"}
|
||||
onChange={(item) => {
|
||||
setErrors(item.target.checked);
|
||||
}}
|
||||
value={"only_errors"}
|
||||
disabled={traceStarted}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.startButton}>
|
||||
{!traceStarted && (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={traceStarted}
|
||||
onClick={startTrace}
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
)}
|
||||
{traceStarted && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={stopTrace}
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
|
||||
<TableWrapper
|
||||
itemActions={[]}
|
||||
columns={[
|
||||
{
|
||||
label: "Time",
|
||||
elementKey: "ptime",
|
||||
renderFunction: (time: Date) => {
|
||||
const timeParse = new Date(time);
|
||||
return timeFromDate(timeParse);
|
||||
},
|
||||
globalClass: classes.timeItem,
|
||||
},
|
||||
{ label: "Name", elementKey: "api" },
|
||||
{
|
||||
label: "Status",
|
||||
elementKey: "",
|
||||
renderFunction: (fullElement: TraceMessage) =>
|
||||
`${fullElement.statusCode} ${fullElement.statusMsg}`,
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: "Location",
|
||||
elementKey: "configuration_id",
|
||||
renderFunction: (fullElement: TraceMessage) =>
|
||||
`${fullElement.host} ${fullElement.client}`,
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: "Load Time",
|
||||
elementKey: "callStats.duration",
|
||||
globalClass: classes.timeItem,
|
||||
},
|
||||
{
|
||||
label: "Upload",
|
||||
elementKey: "callStats.rx",
|
||||
renderFunction: niceBytes,
|
||||
globalClass: classes.sizeItem,
|
||||
},
|
||||
{
|
||||
label: "Download",
|
||||
elementKey: "callStats.tx",
|
||||
renderFunction: niceBytes,
|
||||
globalClass: classes.sizeItem,
|
||||
},
|
||||
]}
|
||||
isLoading={false}
|
||||
records={messages}
|
||||
entityName="Traces"
|
||||
idField="api"
|
||||
customEmptyMessage={
|
||||
traceStarted
|
||||
? "No Traced elements received yet"
|
||||
: "Trace is not started yet"
|
||||
}
|
||||
customPaperHeight={classes.tableWrapper}
|
||||
autoScrollToBottom
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<TextField
|
||||
placeholder="Status Code"
|
||||
className={classes.searchField}
|
||||
id="status-code"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={statusCode}
|
||||
onChange={(e) => {
|
||||
setStatusCode(e.target.value);
|
||||
}}
|
||||
disabled={traceStarted}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Method"
|
||||
className={classes.searchField}
|
||||
id="method"
|
||||
label=""
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={method}
|
||||
onChange={(e) => {
|
||||
setMethod(e.target.value);
|
||||
}}
|
||||
disabled={traceStarted}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Function Name"
|
||||
className={classes.searchField}
|
||||
id="func-name"
|
||||
label=""
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={func}
|
||||
onChange={(e) => {
|
||||
setFunc(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
placeholder="Path"
|
||||
className={classes.searchField}
|
||||
id="path"
|
||||
label=""
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
value={path}
|
||||
onChange={(e) => {
|
||||
setPath(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
type="number"
|
||||
className={classes.searchField}
|
||||
id="fthreshold"
|
||||
label="Response Threshold"
|
||||
disabled={traceStarted}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
inputProps={{
|
||||
min: 0,
|
||||
}}
|
||||
value={threshold}
|
||||
onChange={(e) => {
|
||||
setThreshold(parseInt(e.target.value));
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.inlineCheckboxes}>
|
||||
<span className={classes.labelCheckboxes}>Calls to trace:</span>
|
||||
<CheckboxWrapper
|
||||
checked={all}
|
||||
id={"all_calls"}
|
||||
name={"all_calls"}
|
||||
label={"All"}
|
||||
onChange={(item) => {
|
||||
setAll(item.target.checked);
|
||||
}}
|
||||
value={"all"}
|
||||
disabled={traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={s3 || all}
|
||||
id={"s3_calls"}
|
||||
name={"s3_calls"}
|
||||
label={"S3"}
|
||||
onChange={(item) => {
|
||||
setS3(item.target.checked);
|
||||
}}
|
||||
value={"s3"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={internal || all}
|
||||
id={"internal_calls"}
|
||||
name={"internal_calls"}
|
||||
label={"Internal"}
|
||||
onChange={(item) => {
|
||||
setInternal(item.target.checked);
|
||||
}}
|
||||
value={"internal"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={storage || all}
|
||||
id={"storage_calls"}
|
||||
name={"storage_calls"}
|
||||
label={"Storage"}
|
||||
onChange={(item) => {
|
||||
setStorage(item.target.checked);
|
||||
}}
|
||||
value={"storage"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
checked={os || all}
|
||||
id={"os_calls"}
|
||||
name={"os_calls"}
|
||||
label={"OS"}
|
||||
onChange={(item) => {
|
||||
setOS(item.target.checked);
|
||||
}}
|
||||
value={"os"}
|
||||
disabled={all || traceStarted}
|
||||
/>
|
||||
<span className={classes.labelCheckboxes}>
|
||||
|
|
||||
</span>
|
||||
<CheckboxWrapper
|
||||
checked={errors}
|
||||
id={"only_errors"}
|
||||
name={"only_errors"}
|
||||
label={"Display only Errors"}
|
||||
onChange={(item) => {
|
||||
setErrors(item.target.checked);
|
||||
}}
|
||||
value={"only_errors"}
|
||||
disabled={traceStarted}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.startButton}>
|
||||
{!traceStarted && (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={traceStarted}
|
||||
onClick={startTrace}
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
)}
|
||||
{traceStarted && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={stopTrace}
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
|
||||
<TableWrapper
|
||||
itemActions={[]}
|
||||
columns={[
|
||||
{
|
||||
label: "Time",
|
||||
elementKey: "ptime",
|
||||
renderFunction: (time: Date) => {
|
||||
const timeParse = new Date(time);
|
||||
return timeFromDate(timeParse);
|
||||
},
|
||||
globalClass: classes.timeItem,
|
||||
},
|
||||
{ label: "Name", elementKey: "api" },
|
||||
{
|
||||
label: "Status",
|
||||
elementKey: "",
|
||||
renderFunction: (fullElement: TraceMessage) =>
|
||||
`${fullElement.statusCode} ${fullElement.statusMsg}`,
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: "Location",
|
||||
elementKey: "configuration_id",
|
||||
renderFunction: (fullElement: TraceMessage) =>
|
||||
`${fullElement.host} ${fullElement.client}`,
|
||||
renderFullObject: true,
|
||||
},
|
||||
{
|
||||
label: "Load Time",
|
||||
elementKey: "callStats.duration",
|
||||
globalClass: classes.timeItem,
|
||||
},
|
||||
{
|
||||
label: "Upload",
|
||||
elementKey: "callStats.rx",
|
||||
renderFunction: niceBytes,
|
||||
globalClass: classes.sizeItem,
|
||||
},
|
||||
{
|
||||
label: "Download",
|
||||
elementKey: "callStats.tx",
|
||||
renderFunction: niceBytes,
|
||||
globalClass: classes.sizeItem,
|
||||
},
|
||||
]}
|
||||
isLoading={false}
|
||||
records={messages}
|
||||
entityName="Traces"
|
||||
idField="api"
|
||||
customEmptyMessage={
|
||||
traceStarted
|
||||
? "No Traced elements received yet"
|
||||
: "Trace is not started yet"
|
||||
}
|
||||
customPaperHeight={classes.tableWrapper}
|
||||
autoScrollToBottom
|
||||
/>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@@ -14,7 +14,15 @@
|
||||
// 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 { Button, Grid, TextField, InputBase } from "@mui/material";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Grid,
|
||||
InputBase,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
@@ -22,10 +30,9 @@ import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { AppState } from "../../../store";
|
||||
import { watchMessageReceived, watchResetMessages } from "./actions";
|
||||
import { EventInfo, BucketList, Bucket } from "./types";
|
||||
import { Bucket, BucketList, EventInfo } from "./types";
|
||||
import { niceBytes, timeFromDate } from "../../../common/utils";
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import { FormControl, MenuItem, Select } from "@mui/material";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
@@ -35,6 +42,7 @@ import { ErrorResponseHandler } from "../../../common/types";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import api from "../../../common/api";
|
||||
import BackLink from "../../../common/BackLink";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -183,8 +191,11 @@ const Watch = ({
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PageHeader label="Watch" />
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid container className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
<BackLink to="/tools" label="Return to Tools" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<FormControl variant="outlined">
|
||||
<Select
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { createTheme, adaptV4Theme } from "@mui/material";
|
||||
|
||||
const newTheme = createTheme(
|
||||
adaptV4Theme({
|
||||
palette: {
|
||||
primary: {
|
||||
light: "#0c4453",
|
||||
main: "#01262e",
|
||||
dark: "#001115",
|
||||
contrastText: "#fff",
|
||||
},
|
||||
secondary: {
|
||||
light: "#ff7961",
|
||||
main: "#f44336",
|
||||
dark: "#01262E",
|
||||
contrastText: "#000",
|
||||
},
|
||||
grey: {
|
||||
100: "#F7F7F7",
|
||||
200: "#D8DDDE",
|
||||
300: "#BAC3C5",
|
||||
400: "#9BA9AC",
|
||||
500: "#7C8F93",
|
||||
600: "#5D7479",
|
||||
700: "#3F5A60",
|
||||
800: "#204047",
|
||||
900: "#01262E",
|
||||
},
|
||||
background: {
|
||||
default: "#F4F4F4",
|
||||
},
|
||||
success: {
|
||||
main: "#4ccb92",
|
||||
},
|
||||
warning: {
|
||||
main: "#ffb300",
|
||||
},
|
||||
error: {
|
||||
light: "#e03a48",
|
||||
main: "#dc1f2e",
|
||||
contrastText: "#ffffff",
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: ["Lato", "sans-serif"].join(","),
|
||||
h1: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
h2: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
h3: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
h4: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
h5: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
h6: {
|
||||
fontWeight: "bold",
|
||||
color: "#01262E",
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default newTheme;
|
||||
Reference in New Issue
Block a user