Add Help Box to multiple Screens (#1129)

This commit is contained in:
Daniel Valdivia
2021-10-19 19:15:58 -07:00
committed by GitHub
parent 67082e1b1d
commit 1d69024e3a
9 changed files with 445 additions and 237 deletions

View File

@@ -0,0 +1,66 @@
// 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, { Component } from "react";
import Grid from "@material-ui/core/Grid";
import { createStyles } from "@material-ui/core";
import { Theme, withStyles } from "@material-ui/core/styles";
const styles = (theme: Theme) =>
createStyles({
root: {
border: "1px solid rgb(234, 237, 238)",
borderRadius: 5,
marginTop: 10,
marginBottom: 10,
backgroundColor: "#fbfafa",
},
icon: {
textAlign: "center",
padding: 30,
fontSize: 64,
"& .MuiSvgIcon-root": {
fontSize: 64,
},
},
iconSize: {
fontSize: 64,
},
helpText: { padding: 30, paddingLeft: 0, fontSize: 16 },
});
interface IHelpBox {
classes: any;
iconComponent: any;
help: any;
}
const HelpBox = ({ classes, iconComponent, help }: IHelpBox) => {
return (
<div className={classes.root}>
<Grid container>
<Grid xs={2} className={classes.icon}>
{iconComponent}
</Grid>
<Grid xs={10} className={classes.helpText}>
{help}
</Grid>
</Grid>
</div>
);
};
export default withStyles(styles)(HelpBox);

View File

@@ -20,7 +20,7 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { Button } from "@material-ui/core";
import get from "lodash/get";
import Grid from "@material-ui/core/Grid";
import { AddIcon } from "../../../../icons";
import { AddIcon, LambdaIcon, TiersIcon } from "../../../../icons";
import { BucketEvent, BucketEventList } from "../types";
import { setErrorSnackMessage } from "../../../../actions";
import { AppState } from "../../../../store";
@@ -33,6 +33,7 @@ import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import api from "../../../../common/api";
import DeleteEvent from "./DeleteEvent";
import AddEvent from "./AddEvent";
import HelpBox from "../../../../common/HelpBox";
const styles = (theme: Theme) =>
createStyles({
@@ -41,6 +42,9 @@ const styles = (theme: Theme) =>
actionsTray: {
...actionsTray.actionsTray,
},
twHeight: {
minHeight: 400,
},
});
interface IBucketEventsProps {
@@ -159,6 +163,30 @@ const BucketEventsPanel = ({
records={records}
entityName="Events"
idField="id"
customPaperHeight={classes.twHeight}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<LambdaIcon />}
help={
<Fragment>
MinIO bucket notifications allow administrators to send
notifications to supported external services on certain object
or bucket events. MinIO supports bucket and object-level S3
events similar to the Amazon S3 Event Notifications.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/monitoring/bucket-notifications/bucket-notifications.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
}
/>
</Grid>
</Grid>

View File

@@ -22,7 +22,7 @@ import get from "lodash/get";
import * as reactMoment from "react-moment";
import Grid from "@material-ui/core/Grid";
import { LifeCycleItem } from "../types";
import { AddIcon } from "../../../../icons";
import { AddIcon, TiersIcon } from "../../../../icons";
import {
actionsTray,
searchField,
@@ -34,11 +34,15 @@ import api from "../../../../common/api";
import EditLifecycleConfiguration from "./EditLifecycleConfiguration";
import AddLifecycleModal from "./AddLifecycleModal";
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import HelpBox from "../../../../common/HelpBox";
const styles = (theme: Theme) =>
createStyles({
...searchField,
...actionsTray,
twHeight: {
minHeight: 400,
},
});
interface IBucketLifecyclePanelProps {
@@ -199,6 +203,30 @@ const BucketLifecyclePanel = ({
entityName="Lifecycle"
customEmptyMessage="There are no Lifecycle rules yet"
idField="id"
customPaperHeight={classes.twHeight}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<TiersIcon />}
help={
<Fragment>
MinIO Object Lifecycle Management allows creating rules for time
or date based automatic transition or expiry of objects. For
object transition, MinIO automatically moves the object to a
configured remote storage tier.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/lifecycle-management/lifecycle-management-overview.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
}
/>
</Grid>
</Grid>

View File

@@ -19,7 +19,7 @@ import { connect } from "react-redux";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { Button } from "@material-ui/core";
import Grid from "@material-ui/core/Grid";
import { AddIcon } from "../../../../icons";
import { AddIcon, BucketsIcon, TiersIcon } from "../../../../icons";
import { setErrorSnackMessage } from "../../../../actions";
import {
actionsTray,
@@ -37,6 +37,7 @@ import api from "../../../../common/api";
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import AddReplicationModal from "./AddReplicationModal";
import DeleteReplicationRule from "./DeleteReplicationRule";
import HelpBox from "../../../../common/HelpBox";
interface IBucketReplicationProps {
classes: any;
@@ -49,6 +50,9 @@ const styles = (theme: Theme) =>
createStyles({
...searchField,
...actionsTray,
twHeight: {
minHeight: 400,
},
});
const BucketReplicationPanel = ({
@@ -235,6 +239,28 @@ const BucketReplicationPanel = ({
records={replicationRules}
entityName="Replication Rules"
idField="id"
customPaperHeight={classes.twHeight}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<BucketsIcon />}
help={
<Fragment>
MinIO supports server-side and client-side replication of
objects between source and destination buckets.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/replication/replication-overview.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
}
/>
</Grid>
</Grid>

View File

@@ -14,7 +14,13 @@
// 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, Fragment } from "react";
import React, {
useEffect,
useState,
Fragment,
ReactComponentElement,
Component,
} from "react";
import get from "lodash/get";
import { connect } from "react-redux";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
@@ -29,7 +35,7 @@ import {
settingsCommon,
typesSelection,
} from "../../Common/FormComponents/common/styleLibrary";
import { AddIcon } from "../../../../icons";
import { AddIcon, TiersIcon } from "../../../../icons";
import { setErrorSnackMessage } from "../../../../actions";
import { ITierElement, ITierResponse } from "./types";
import { ErrorResponseHandler } from "../../../../common/types";
@@ -40,6 +46,8 @@ import UpdateTierCredentiasModal from "./UpdateTierCredentiasModal";
import RefreshIcon from "../../../../icons/RefreshIcon";
import SearchIcon from "../../../../icons/SearchIcon";
import PageHeader from "../../Common/PageHeader/PageHeader";
import theme from "../../../../theme/main";
import HelpBox from "../../../../common/HelpBox";
interface IListTiersConfig {
classes: any;
@@ -64,14 +72,7 @@ const styles = (theme: Theme) =>
lineHeight: "24px",
},
customConfigurationPage: {
height: "calc(100vh - 210px)",
scrollbarWidth: "none" as const,
"&::-webkit-scrollbar": {
display: "none",
},
},
lambdaContainer: {
padding: "15px 0",
minHeight: 400,
},
actionsTray: {
...actionsTray.actionsTray,
@@ -193,105 +194,122 @@ const ListTiersConfiguration = ({
)}
<PageHeader label="Tiers" />
<Grid container className={classes.container}>
<Fragment>
<Grid item xs={12} className={classes.lambdaContainer}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Filter"
className={classes.searchField}
id="search-resource"
label=""
onChange={(event) => {
setFilter(event.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
<IconButton
color="primary"
aria-label="Refresh List"
component="span"
onClick={() => {
setIsLoading(true);
}}
>
<RefreshIcon />
</IconButton>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={addTier}
>
Add Tier
</Button>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={[
{
type: "edit",
onClick: (tierData: ITierElement) => {
setSelectedTier(tierData);
setUpdateCredentialsOpen(true);
},
},
]}
columns={[
{
label: "Tier Name",
elementKey: "type",
renderFunction: renderTierName,
renderFullObject: true,
},
{
label: "Type",
elementKey: "type",
width: 150,
},
{
label: "Endpoint",
elementKey: "type",
renderFunction: renderTierEndpoint,
renderFullObject: true,
},
{
label: "Bucket",
elementKey: "type",
renderFunction: renderTierBucket,
renderFullObject: true,
},
{
label: "Prefix",
elementKey: "type",
renderFunction: renderTierPrefix,
renderFullObject: true,
},
{
label: "Region",
elementKey: "type",
renderFunction: renderTierRegion,
renderFullObject: true,
},
]}
isLoading={isLoading}
records={filteredRecords}
entityName="Tiers"
idField="service_name"
customPaperHeight={classes.customConfigurationPage}
/>
</Grid>
</Grid>
</Fragment>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Filter"
className={classes.searchField}
id="search-resource"
label=""
onChange={(event) => {
setFilter(event.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
<IconButton
color="primary"
aria-label="Refresh List"
component="span"
onClick={() => {
setIsLoading(true);
}}
>
<RefreshIcon />
</IconButton>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={addTier}
>
Add Tier
</Button>
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={[
{
type: "edit",
onClick: (tierData: ITierElement) => {
setSelectedTier(tierData);
setUpdateCredentialsOpen(true);
},
},
]}
columns={[
{
label: "Tier Name",
elementKey: "type",
renderFunction: renderTierName,
renderFullObject: true,
},
{
label: "Type",
elementKey: "type",
width: 150,
},
{
label: "Endpoint",
elementKey: "type",
renderFunction: renderTierEndpoint,
renderFullObject: true,
},
{
label: "Bucket",
elementKey: "type",
renderFunction: renderTierBucket,
renderFullObject: true,
},
{
label: "Prefix",
elementKey: "type",
renderFunction: renderTierPrefix,
renderFullObject: true,
},
{
label: "Region",
elementKey: "type",
renderFunction: renderTierRegion,
renderFullObject: true,
},
]}
isLoading={isLoading}
records={filteredRecords}
entityName="Tiers"
idField="service_name"
customPaperHeight={classes.customConfigurationPage}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<TiersIcon />}
help={
<Fragment>
Tiers are used by the MinIO Object Lifecycle Management which
allows creating rules for time or date based automatic
transition or expiry of objects. For object transition, MinIO
automatically moves the object to a configured remote storage
tier.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/lifecycle-management/lifecycle-management-overview.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
}
/>
</Grid>
</Grid>
</Fragment>
);

View File

@@ -369,7 +369,7 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
<Grid
item
xs={12}
lg={8}
lg={12}
className={`${classes.licenseContainer}`}
>
{licenseInfo ? (
@@ -519,7 +519,7 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
</Fragment>
)}
</Grid>
<Grid item xs={12} lg={4} className={`${classes.paper}`}>
<Grid item xs={12} lg={12} className={`${classes.paper}`}>
{licenseInfo ? (
<Fragment>
<Typography
@@ -590,28 +590,32 @@ const License = ({ classes, operatorMode }: ILicenseProps) => {
more about the compliance policy.
</Typography>
<br />
<a
href={`https://min.io/compliance?ref=${
operatorMode ? "op" : "con"
}`}
className={classes.openSourcePolicy}
target="_blank"
rel="nofollow noopener noreferrer"
>
Open Source Policy Compliance
</a>
<br />
<br />
<a
href={`https://min.io/logo?ref=${
operatorMode ? "op" : "con"
}`}
className={classes.openSourcePolicy}
target="_blank"
rel="nofollow noopener noreferrer"
>
Trademark Policy
</a>
<ul>
<li>
<a
href={`https://min.io/compliance?ref=${
operatorMode ? "op" : "con"
}`}
className={classes.openSourcePolicy}
target="_blank"
rel="nofollow noopener noreferrer"
>
Learn more about GNU AGPL v3
</a>
</li>
<li>
<a
href={`https://min.io/logo?ref=${
operatorMode ? "op" : "con"
}`}
className={classes.openSourcePolicy}
target="_blank"
rel="nofollow noopener noreferrer"
>
MinIO Trademark Compliance
</a>
</li>
</ul>
</Fragment>
)}
</Grid>

View File

@@ -29,7 +29,7 @@ import {
TransformedEndpointItem,
} from "./types";
import { notificationTransform } from "./utils";
import { AddIcon } from "../../../icons";
import { AddIcon, LambdaIcon } from "../../../icons";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
import { setErrorSnackMessage } from "../../../actions";
import {
@@ -43,6 +43,7 @@ import api from "../../../common/api";
import RefreshIcon from "../../../icons/RefreshIcon";
import SearchIcon from "../../../icons/SearchIcon";
import history from "../../../history";
import HelpBox from "../../../common/HelpBox";
interface IListNotificationEndpoints {
classes: any;
@@ -64,12 +65,8 @@ const styles = (theme: Theme) =>
iconText: {
lineHeight: "24px",
},
customConfigurationPage: {
height: "calc(100vh - 410px)",
scrollbarWidth: "none" as const,
"&::-webkit-scrollbar": {
display: "none",
},
twHeight: {
minHeight: 400,
},
lambdaContainer: {
padding: "15px 0",
@@ -138,7 +135,7 @@ const ListNotificationEndpoints = ({
return (
<Fragment>
<Grid container>
<Grid container className={classes.container}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Filter"
@@ -179,34 +176,46 @@ const ListNotificationEndpoints = ({
</Button>
</Grid>
<Grid item xs={12}>
<Grid item xs={12}>
<div className={classes.settingsOptionsContainer}>
<TableWrapper
itemActions={[]}
columns={[
{
label: "Status",
elementKey: "status",
renderFunction: statusDisplay,
width: 150,
},
{ label: "Service", elementKey: "service_name" },
]}
isLoading={isLoading}
records={filteredRecords}
entityName="Notification Endpoints"
idField="service_name"
customPaperHeight={classes.twHeight}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<LambdaIcon />}
help={
<Fragment>
<Grid item xs={12} className={classes.lambdaContainer}>
<Grid item xs={12}>
<TableWrapper
itemActions={[]}
columns={[
{
label: "Status",
elementKey: "status",
renderFunction: statusDisplay,
width: 150,
},
{ label: "Service", elementKey: "service_name" },
]}
isLoading={isLoading}
records={filteredRecords}
entityName="Notification Endpoints"
idField="service_name"
customPaperHeight={classes.customConfigurationPage}
noBackground
/>
</Grid>
</Grid>
MinIO bucket notifications allow administrators to send
notifications to supported external services on certain object
or bucket events. MinIO supports bucket and object-level S3
events similar to the Amazon S3 Event Notifications.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/monitoring/bucket-notifications/bucket-notifications.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
</div>
</Grid>
}
/>
</Grid>
</Grid>
</Fragment>

View File

@@ -50,11 +50,7 @@ const NotificationEndpoints = ({
return (
<Fragment>
<PageHeader label="Notification Endpoints" />
<Grid container className={classes.container}>
<Grid item xs={12}>
<ListNotificationEndpoints />
</Grid>
</Grid>
<ListNotificationEndpoints />
</Fragment>
);
};

View File

@@ -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, { useCallback, useEffect, useState } from "react";
import React, { Fragment, useCallback, useEffect, useState } from "react";
import { connect } from "react-redux";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../common/api";
@@ -22,7 +22,7 @@ import { Button, Grid, InputAdornment, TextField } from "@material-ui/core";
import GroupIcon from "@material-ui/icons/Group";
import { User, UsersList } from "./types";
import { usersSort } from "../../../utils/sortFunctions";
import { AddIcon } from "../../../icons";
import { AddIcon, LambdaIcon, UsersIcon } from "../../../icons";
import {
actionsTray,
containerForHeader,
@@ -38,6 +38,7 @@ import SetPolicy from "../Policies/SetPolicy";
import PageHeader from "../Common/PageHeader/PageHeader";
import SearchIcon from "../../../icons/SearchIcon";
import { decodeFileName } from "../../../common/utils";
import HelpBox from "../../../common/HelpBox";
const styles = (theme: Theme) =>
createStyles({
@@ -71,6 +72,9 @@ const styles = (theme: Theme) =>
},
},
},
twHeight: {
minHeight: 600,
},
...actionsTray,
...searchField,
...containerForHeader(theme.spacing(4)),
@@ -219,67 +223,96 @@ const ListUsers = ({ classes, setErrorSnackMessage, history }: IUsersProps) => {
/>
)}
<PageHeader label={"Users"} />
<Grid container>
<Grid item xs={12} className={classes.container}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Search Users"
className={classes.searchField}
id="search-resource"
label=""
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
onChange={(e) => {
setFilter(e.target.value);
}}
/>
<Button
variant="contained"
color="primary"
startIcon={<GroupIcon />}
disabled={checkedUsers.length <= 0}
onClick={() => {
if (checkedUsers.length > 0) {
setAddGroupOpen(true);
}
}}
>
Add to Group
</Button>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => {
setAddScreenOpen(true);
setSelectedUser(null);
}}
>
Create User
</Button>
</Grid>
<Grid container className={classes.container}>
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Search Users"
className={classes.searchField}
id="search-resource"
label=""
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
onChange={(e) => {
setFilter(e.target.value);
}}
/>
<Button
variant="contained"
color="primary"
startIcon={<GroupIcon />}
disabled={checkedUsers.length <= 0}
onClick={() => {
if (checkedUsers.length > 0) {
setAddGroupOpen(true);
}
}}
>
Add to Group
</Button>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => {
setAddScreenOpen(true);
setSelectedUser(null);
}}
>
Create User
</Button>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={tableActions}
columns={[{ label: "Access Key", elementKey: "accessKey" }]}
onSelect={selectionChanged}
selectedItems={checkedUsers}
isLoading={loading}
records={filteredRecords}
entityName="Users"
idField="accessKey"
/>
</Grid>
<Grid item xs={12}>
<br />
</Grid>
<Grid item xs={12}>
<TableWrapper
itemActions={tableActions}
columns={[{ label: "Access Key", elementKey: "accessKey" }]}
onSelect={selectionChanged}
selectedItems={checkedUsers}
isLoading={loading}
records={filteredRecords}
entityName="Users"
idField="accessKey"
customPaperHeight={classes.twHeight}
/>
</Grid>
<Grid item xs={12}>
<HelpBox
iconComponent={<UsersIcon />}
help={
<Fragment>
A MinIO user consists of a unique access key (username) and
corresponding secret key (password). Clients must authenticate
their identity by specifying both a valid access key (username)
and the corresponding secret key (password) of an existing MinIO
user.
<br />
<br />
Each user can have one or more assigned policies that explicitly
list the actions and resources to which that user has access.
Users can also inherit policies from the groups in which they
have membership.
<br />
<br />
You can learn more at our{" "}
<a
href="https://docs.min.io/minio/baremetal/monitoring/bucket-notifications/bucket-notifications.html?ref=con"
target="_blank"
>
documentation
</a>
.
</Fragment>
}
/>
</Grid>
</Grid>
</React.Fragment>