Tables replacement in mcs (#74)

Replaced all the tables in mcs to be consistent with the new design

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2020-04-21 17:38:46 -05:00
committed by GitHub
parent 5fa0a0fca8
commit d9c212fe2f
15 changed files with 530 additions and 693 deletions

File diff suppressed because one or more lines are too long

View File

@@ -16,34 +16,20 @@
import React from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import api from "../../../../common/api";
import { Bucket, BucketList } from "../types";
import {
Button,
IconButton,
LinearProgress,
TableFooter,
TablePagination
} from "@material-ui/core";
import { Button } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import DeleteIcon from "@material-ui/icons/Delete";
import AddBucket from "./AddBucket";
import DeleteBucket from "./DeleteBucket";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import Moment from "react-moment";
import { Link } from "react-router-dom";
import ViewIcon from "@material-ui/icons/Visibility";
import api from "../../../../common/api";
import { Bucket, BucketList } from "../types";
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
import AddBucket from "./AddBucket";
import DeleteBucket from "./DeleteBucket";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
const styles = (theme: Theme) =>
createStyles({
@@ -134,8 +120,8 @@ class ListBuckets extends React.Component<
.then((res: BucketList) => {
this.setState({
loading: false,
records: res.buckets,
totalRecords: res.total,
records: res.buckets || [],
totalRecords: !res.buckets ? 0 : res.total,
error: ""
});
// if we get 0 results, and page > 0 , go down 1 page
@@ -208,6 +194,29 @@ class ListBuckets extends React.Component<
this.setState({ deleteOpen: true, selectedBucket: bucket });
};
const tableActions = [
{ type: "view", to: `/buckets`, sendOnlyId: true },
{ type: "delete", onClick: confirmDeleteBucket, sendOnlyId: true }
];
const displayParsedDate = (date: string) => {
return <Moment>{date}</Moment>;
};
const filteredRecords = records
.slice(offset, offset + rowsPerPage)
.filter((b: Bucket) => {
if (filterBuckets === "") {
return true;
} else {
if (b.name.indexOf(filterBuckets) >= 0) {
return true;
} else {
return false;
}
}
});
return (
<React.Fragment>
{addScreenOpen && (
@@ -271,78 +280,35 @@ class ListBuckets extends React.Component<
<br />
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}
{records != null && records.length > 0 ? (
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Creation Date</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{records
.slice(offset, offset + rowsPerPage)
.filter((b: Bucket) => {
if (filterBuckets === "") {
return true;
} else {
if (b.name.indexOf(filterBuckets) >= 0) {
return true;
} else {
return false;
}
}
})
.map(row => (
<TableRow key={row.name}>
<TableCell>{row.name}</TableCell>
<TableCell>
<Moment>{row.creation_date}</Moment>
</TableCell>
<TableCell align="right">
<Link to={`/buckets/${row.name}`}>
<IconButton aria-label="delete">
<ViewIcon />
</IconButton>
</Link>
<IconButton
aria-label="delete"
onClick={() => {
confirmDeleteBucket(row.name);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={3}
count={totalRecords}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { "aria-label": "rows per page" },
native: true
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={MinTablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
) : (
<div>No Buckets</div>
)}
</Paper>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "Name", elementKey: "name" },
{
label: "Creation Date",
elementKey: "creation_date",
renderFunction: displayParsedDate
}
]}
isLoading={loading}
records={filteredRecords}
entityName="Buckets"
idField="name"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions
}}
/>
</Grid>
</Grid>
</React.Fragment>

View File

@@ -67,6 +67,7 @@ class DeleteEvent extends React.Component<
if (bucketEvent == null) {
return;
}
this.setState({ deleteLoading: true }, () => {
api
.invoke(

View File

@@ -16,29 +16,17 @@
import React from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import api from "../../../../common/api";
import { BucketEvent, BucketEventList, BucketInfo } from "../types";
import {
Button,
IconButton,
LinearProgress,
TableFooter,
TablePagination
} from "@material-ui/core";
import { Button } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import DeleteIcon from "@material-ui/icons/Delete";
import SetAccessPolicy from "./SetAccessPolicy";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
import AddEvent from "./AddEvent";
import DeleteEvent from "./DeleteEvent";
import TableWrapper from "../../Common/TableWrapper/TableWrapper";
const styles = (theme: Theme) =>
createStyles({
@@ -135,19 +123,16 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
api
.invoke("GET", `/api/v1/buckets/${bucketName}/events`)
.then((res: BucketEventList) => {
const events = res.events;
this.setState({
loading: false,
records: res.events,
records: events || [],
totalRecords: res.total,
error: ""
});
// if we get 0 results, and page > 0 , go down 1 page
if (
(res.events === undefined ||
res.events == null ||
res.events.length === 0) &&
page > 0
) {
if ((!events || res.events.length === 0) && page > 0) {
const newPage = page - 1;
this.setState({ page: newPage }, () => {
this.fetchEvents();
@@ -231,6 +216,14 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
accessPolicy = info.access;
}
const eventsDisplay = (events: string[]) => {
return <React.Fragment>{events.join(", ")}</React.Fragment>;
};
const tableActions = [{ type: "delete", onClick: confirmDeleteEvent }];
const filteredRecords = records.slice(offset, offset + rowsPerPage);
return (
<React.Fragment>
<AddEvent
@@ -301,66 +294,37 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
<br />
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}
{records != null && records.length > 0 ? (
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>SQS</TableCell>
<TableCell>Events</TableCell>
<TableCell>Prefix</TableCell>
<TableCell>Suffix</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{records
.slice(offset, offset + rowsPerPage)
.map((row, index) => (
<TableRow
key={`bucket-evt-${row.id}-${index.toString()}`}
>
<TableCell>{row.arn}</TableCell>
<TableCell>{row.events.join(", ")}</TableCell>
<TableCell>{row.prefix}</TableCell>
<TableCell>{row.suffix}</TableCell>
<TableCell align="right">
<IconButton
aria-label="delete"
onClick={() => {
confirmDeleteEvent(row);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={3}
count={totalRecords}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { "aria-label": "rows per page" },
native: true
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={MinTablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
) : (
<div className={classes.noRecords}>No Events</div>
)}
</Paper>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "SQS", elementKey: "arn" },
{
label: "Events",
elementKey: "events",
renderFunction: eventsDisplay
},
{ label: "Prefix", elementKey: "prefix" },
{ label: "Suffix", elementKey: "suffix" }
]}
isLoading={loading}
records={filteredRecords}
entityName="Events"
idField="id"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions
}}
/>
</Grid>
</Grid>

View File

@@ -14,16 +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/>.
import React from "react";
import isString from "lodash/isString";
import { IconButton } from "@material-ui/core";
import ViewIcon from "./TableActionIcons/ViewIcon";
import PencilIcon from "./TableActionIcons/PencilIcon";
import DeleteIcon from "./TableActionIcons/DeleteIcon";
import { Link } from "react-router-dom";
interface IActionButton {
type: string;
onClick: (id: string) => any;
onClick?: (id: string) => any;
to?: string;
valueToSend: any;
selected: boolean;
sendOnlyId?: boolean;
idField: string;
}
const defineIcon = (type: string, selected: boolean) => {
@@ -43,18 +48,37 @@ const TableActionButton = ({
type,
onClick,
valueToSend,
selected
idField,
selected,
to,
sendOnlyId = false
}: IActionButton) => {
return (
const valueClick = sendOnlyId ? valueToSend[idField] : valueToSend;
const buttonElement = (
<IconButton
aria-label={type}
onClick={() => {
onClick(valueToSend);
}}
onClick={
onClick
? () => {
onClick(valueClick);
}
: () => null
}
>
{defineIcon(type, selected)}
</IconButton>
);
if (onClick) {
return buttonElement;
}
if (isString(to)) {
return <Link to={`${to}/${valueClick}`}>{buttonElement}</Link>;
}
return null;
};
export default TableActionButton;

View File

@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import get from "lodash/get";
import isString from "lodash/isString";
import {
LinearProgress,
TablePagination,
@@ -31,15 +32,20 @@ import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { TablePaginationActionsProps } from "@material-ui/core/TablePagination/TablePaginationActions";
import TableActionButton from "./TableActionButton";
//Interfaces for table Items
interface ItemActions {
type: string;
onClick(valueToSend: any): any;
onClick?(valueToSend: any): any;
to?: string;
sendOnlyId?: boolean;
}
interface IColumns {
label: string;
elementKey: string;
sortable?: boolean;
renderFunction?: (input: any) => any;
}
interface IPaginatorConfig {
@@ -144,59 +150,66 @@ const styles = (theme: Theme) =>
}
});
// Function that renders Title Columns
const titleColumnsMap = (columns: IColumns[]) => {
const columnsList = columns.map((column: IColumns, index: number) => {
return columns.map((column: IColumns, index: number) => {
return (
<TableCell key={`tbCT-${column.elementKey}-${index}`}>
{column.label}
</TableCell>
);
});
return columnsList;
};
// Function that renders Rows
const rowColumnsMap = (
columns: IColumns[],
itemData: any,
classes: any,
isSelected: boolean
) => {
const rowElements = columns.map((column: IColumns, index: number) => {
const itemElement = get(itemData, column.elementKey, null);
return columns.map((column: IColumns, index: number) => {
const itemElement = isString(itemData)
? itemData
: get(itemData, column.elementKey, null); // If the element is just a string, we render it as it is
const renderElement = column.renderFunction
? column.renderFunction(itemElement)
: itemElement; // If render function is set, we send the value to the function.
return (
<TableCell
key={`tbRE-${column.elementKey}-${index}`}
className={isSelected ? classes.rowSelected : classes.rowUnselected}
>
{itemElement}
{renderElement}
</TableCell>
);
});
return rowElements;
};
// Function to render the action buttons
const elementActions = (
actions: ItemActions[],
valueToSend: any,
selected: boolean
selected: boolean,
idField: string
) => {
const actionsElements = actions.map((action: ItemActions, index: number) => {
return actions.map((action: ItemActions, index: number) => {
return (
<TableActionButton
type={action.type}
onClick={action.onClick}
to={action.to}
valueToSend={valueToSend}
selected={selected}
key={`actions-${action.type}-${index.toString()}`}
idField={idField}
sendOnlyId={!!action.sendOnlyId}
/>
);
});
return actionsElements;
};
// Main function to render the Table Wrapper
const TableWrapper = ({
itemActions,
columns,
@@ -241,8 +254,11 @@ const TableWrapper = ({
<TableBody>
{records.map((record: any, index: number) => {
const isSelected = selectedItems
? selectedItems.includes(record[idField])
? selectedItems.includes(
isString(record) ? record : record[idField]
)
: false;
return (
<TableRow key={`tb-${entityName}-${index.toString()}`}>
{onSelect && selectedItems && (
@@ -252,7 +268,7 @@ const TableWrapper = ({
className={classes.checkBoxRow}
>
<Checkbox
value={record[idField]}
value={isString(record) ? record : record[idField]}
color="primary"
inputProps={{ "aria-label": "secondary checkbox" }}
checked={isSelected}
@@ -265,10 +281,15 @@ const TableWrapper = ({
{rowColumnsMap(columns, record, classes, isSelected)}
{itemActions && itemActions.length > 0 && (
<TableCell
align="right"
align="center"
className={classes.actionsContainer}
>
{elementActions(itemActions, record, isSelected)}
{elementActions(
itemActions,
record,
isSelected,
idField
)}
</TableCell>
)}
</TableRow>

View File

@@ -21,21 +21,7 @@ import Typography from "@material-ui/core/Typography";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import {
Button,
IconButton,
LinearProgress,
TableFooter,
TablePagination
} from "@material-ui/core";
import Paper from "@material-ui/core/Paper";
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableCell from "@material-ui/core/TableCell";
import TableBody from "@material-ui/core/TableBody";
import ViewIcon from "@material-ui/icons/Visibility";
import DeleteIcon from "@material-ui/icons/Delete";
import { Button } from "@material-ui/core";
import { CreateIcon } from "../../../icons";
import api from "../../../common/api";
import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions";
@@ -43,6 +29,7 @@ import { GroupsList } from "./types";
import { groupsSort } from "../../../utils/sortFunctions";
import AddGroup from "../Groups/AddGroup";
import DeleteGroup from "./DeleteGroup";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
interface IGroupsProps {
classes: any;
@@ -142,10 +129,7 @@ const Groups = ({ classes }: IGroupsProps) => {
resGroups = res.groups.sort(groupsSort);
}
setRecords(resGroups);
let total = 0;
if (res.total !== null) {
total = res.total;
}
const total = !res.total ? 0 : res.total;
setTotalRecords(total);
setError("");
isLoading(false);
@@ -182,6 +166,21 @@ const Groups = ({ classes }: IGroupsProps) => {
elementItem.includes(filter)
);
const viewAction = (group: any) => {
setGroupOpen(true);
setSelectedGroup(group);
};
const deleteAction = (group: any) => {
setDeleteOpen(true);
setSelectedGroup(group);
};
const tableActions = [
{ type: "view", onClick: viewAction },
{ type: "delete", onClick: deleteAction }
];
return (
<React.Fragment>
{addGroupOpen && (
@@ -241,68 +240,28 @@ const Groups = ({ classes }: IGroupsProps) => {
<br />
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}
{records != null && records.length > 0 ? (
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Name</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredRecords.map(group => (
<TableRow key={`user-${group}`}>
<TableCell className={classes.wrapCell}>
{group}
</TableCell>
<TableCell align="right">
<IconButton
aria-label="view"
onClick={() => {
setGroupOpen(true);
setSelectedGroup(group);
}}
>
<ViewIcon />
</IconButton>
<IconButton
aria-label="delete"
onClick={() => {
setDeleteOpen(true);
setSelectedGroup(group);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={3}
count={totalRecords}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { "aria-label": "rows per page" },
native: true
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={MinTablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
) : (
<div>No Groups Available</div>
)}
</Paper>
<TableWrapper
itemActions={tableActions}
columns={[{ label: "Name", elementKey: "" }]}
isLoading={loading}
records={filteredRecords}
entityName="Groups"
idField=""
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions
}}
/>
</Grid>
</Grid>
</React.Fragment>

View File

@@ -18,22 +18,16 @@ import React, { useState, useEffect } from "react";
import get from "lodash/get";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { LinearProgress } from "@material-ui/core";
import TableContainer from "@material-ui/core/TableContainer";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import Title from "../../../common/Title";
import Checkbox from "@material-ui/core/Checkbox";
import { UsersList } from "../Users/types";
import { usersSort } from "../../../utils/sortFunctions";
import api from "../../../common/api";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
interface IGroupsProps {
classes: any;
@@ -198,40 +192,17 @@ const UsersSelectors = ({
}}
/>
</Grid>
<TableContainer className={classes.tableContainer}>
<Table size="small" stickyHeader aria-label="sticky table">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell className={classes.stickyHeader}>
Select
</TableCell>
<TableCell className={classes.stickyHeader}>
Access Key
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredRecords.map(row => (
<TableRow key={`group-${row.accessKey}`}>
<TableCell padding="checkbox">
<Checkbox
value={row.accessKey}
color="primary"
inputProps={{
"aria-label": "secondary checkbox"
}}
onChange={selectionChanged}
checked={selUsers.includes(row.accessKey)}
/>
</TableCell>
<TableCell className={classes.wrapCell}>
{row.accessKey}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Grid item xs={12}>
<TableWrapper
columns={[{ label: "Access Key", elementKey: "accessKey" }]}
onSelect={selectionChanged}
selectedItems={selUsers}
isLoading={loading}
records={filteredRecords}
entityName="Users"
idField="accessKey"
/>
</Grid>
</React.Fragment>
) : (
<div className={classes.noFound}>No Users Available</div>

View File

@@ -16,33 +16,24 @@
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import {
Button,
IconButton,
LinearProgress,
TableFooter,
TablePagination,
TextField
} from "@material-ui/core";
import { TextField } from "@material-ui/core";
import { red } from "@material-ui/core/colors";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import { CreateIcon } from "../../../icons";
import Paper from "@material-ui/core/Paper";
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableCell from "@material-ui/core/TableCell";
import TableBody from "@material-ui/core/TableBody";
import { Link } from "react-router-dom";
import ViewIcon from "@material-ui/icons/Visibility";
import DeleteIcon from "@material-ui/icons/Delete";
import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions";
import { NotificationEndpointItem, NotificationEndpointsList } from "./types";
import {
NotificationEndpointItem,
NotificationEndpointsList,
TransformedEndpointItem
} from "./types";
import { notificationTransform } from "./utils";
import { CreateIcon } from "../../../icons";
import api from "../../../common/api";
import FiberManualRecordIcon from "@material-ui/icons/FiberManualRecord";
import { red } from "@material-ui/core/colors";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
import AddNotificationEndpoint from "./AddNotificationEndpoint";
interface IListNotificationEndpoints {
@@ -79,7 +70,7 @@ const styles = (theme: Theme) =>
const ListNotificationEndpoints = ({ classes }: IListNotificationEndpoints) => {
//Local States
const [records, setRecords] = useState<NotificationEndpointItem[]>([]);
const [records, setRecords] = useState<TransformedEndpointItem[]>([]);
const [totalRecords, setTotalRecords] = useState<number>(0);
const [rowsPerPage, setRowsPerPage] = useState<number>(10);
const [page, setPage] = useState<number>(0);
@@ -100,7 +91,7 @@ const ListNotificationEndpoints = ({ classes }: IListNotificationEndpoints) => {
if (res.notification_endpoints !== null) {
resNotEndList = res.notification_endpoints;
}
setRecords(resNotEndList);
setRecords(notificationTransform(resNotEndList));
setTotalRecords(resNotEndList.length);
setError("");
setIsLoading(false);
@@ -118,6 +109,44 @@ const ListNotificationEndpoints = ({ classes }: IListNotificationEndpoints) => {
setIsLoading(true);
}, []);
const tableActions = [
{ type: "view", to: "/notification-endpoints", sendOnlyId: true },
{
type: "delete",
onClick: (row: any) => {
//confirmDeleteBucket(row.name);
}
}
];
const filteredRecords = records.filter((b: TransformedEndpointItem) => {
if (filter === "") {
return true;
} else {
if (b.service_name.indexOf(filter) >= 0) {
return true;
} else {
return false;
}
}
});
const statusDisplay = (status: string) => {
return (
<div
style={{
display: "flex",
alignItems: "center"
}}
>
<FiberManualRecordIcon
style={status === "Offline" ? { color: red[500] } : {}}
/>
{status}
</div>
);
};
return (
<React.Fragment>
{addScreenOpen && (
@@ -170,101 +199,42 @@ const ListNotificationEndpoints = ({ classes }: IListNotificationEndpoints) => {
<br />
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
{isLoading && <LinearProgress />}
{records != null && records.length > 0 ? (
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Service</TableCell>
<TableCell>Status</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{records
.filter((b: NotificationEndpointItem) => {
if (filter === "") {
return true;
} else {
if (b.service.indexOf(filter) >= 0) {
return true;
} else {
return false;
}
}
})
.map(row => (
<TableRow key={`${row.service}:${row.account_id}`}>
<TableCell>{`${row.service}:${row.account_id}`}</TableCell>
{/*<TableCell>{row.account_id}</TableCell>*/}
<TableCell className={classes.iconText}>
<div
style={{
display: "flex",
alignItems: "center"
}}
>
<FiberManualRecordIcon
style={
row.status === "Offline"
? { color: red[500] }
: {}
}
/>
{row.status}
</div>
</TableCell>
<TableCell align="right">
<Link
to={`/notification-endpoints/${row.service}:${row.account_id}`}
>
<IconButton aria-label="delete">
<ViewIcon />
</IconButton>
</Link>
<IconButton
aria-label="delete"
onClick={() => {
//confirmDeleteBucket(row.name);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={3}
count={totalRecords}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { "aria-label": "rows per page" },
native: true
}}
onChangePage={(event: unknown, newPage: number) => {
setPage(newPage);
}}
onChangeRowsPerPage={(
event: React.ChangeEvent<HTMLInputElement>
) => {
const rPP = parseInt(event.target.value, 10);
setRowsPerPage(rPP);
}}
ActionsComponent={MinTablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
) : (
<div>No Notification Endpoints</div>
)}
</Paper>
<TableWrapper
itemActions={tableActions}
columns={[
{ label: "Service", elementKey: "service_name" },
{
label: "Status",
elementKey: "status",
renderFunction: statusDisplay
}
]}
isLoading={isLoading}
records={filteredRecords}
entityName="Notification Endpoints"
idField="service_name"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true
},
onChangePage: (event: unknown, newPage: number) => {
setPage(newPage);
},
onChangeRowsPerPage: (
event: React.ChangeEvent<HTMLInputElement>
) => {
const rPP = parseInt(event.target.value, 10);
setRowsPerPage(rPP);
},
ActionsComponent: MinTablePaginationActions
}}
/>
</Grid>
</Grid>
</React.Fragment>

View File

@@ -26,6 +26,11 @@ export interface NotificationEndpointItem {
status: string;
}
export interface TransformedEndpointItem {
service_name: string;
status: string;
}
export interface NotificationEndpointsList {
notification_endpoints: NotificationEndpointItem[];
}

View File

@@ -0,0 +1,28 @@
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { NotificationEndpointItem } from "./types";
export const notificationTransform = (
notificationElements: NotificationEndpointItem[]
) => {
return notificationElements.map(element => {
return {
service_name: `${element.service}:${element.account_id}`,
status: element.status
};
});
};

View File

@@ -16,21 +16,8 @@
import React from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import {
Button,
IconButton,
LinearProgress,
TableFooter,
TablePagination
} from "@material-ui/core";
import DeleteIcon from "@material-ui/icons/Delete";
import { Button } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";
import TextField from "@material-ui/core/TextField";
import InputAdornment from "@material-ui/core/InputAdornment";
@@ -41,7 +28,7 @@ import DeletePolicy from "./DeletePolicy";
import api from "../../../common/api";
import { CreateIcon } from "../../../icons";
import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions";
import VisibilityIcon from "@material-ui/icons/Visibility";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
const styles = (theme: Theme) =>
createStyles({
@@ -206,6 +193,32 @@ class Policies extends React.Component<IPoliciesProps, IPoliciesState> {
this.setState({ deleteOpen: true, selectedPolicy: policy });
};
const viewAction = (row: any) => {
this.setState({
addScreenOpen: true,
policyEdit: row
});
};
const tableActions = [
{ type: "view", onClick: viewAction },
{ type: "delete", onClick: confirmDeletePolicy, sendOnlyId: true }
];
const filteredRecords = records
.slice(offset, offset + rowsPerPage)
.filter((b: Policy) => {
if (filterPolicies === "") {
return true;
} else {
if (b.name.indexOf(filterPolicies) >= 0) {
return true;
} else {
return false;
}
}
});
return (
<React.Fragment>
{addScreenOpen && (
@@ -271,80 +284,28 @@ class Policies extends React.Component<IPoliciesProps, IPoliciesState> {
<br />
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}
{records != null && records.length > 0 ? (
<Table size="medium">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell>Name</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{records
.slice(offset, offset + rowsPerPage)
.filter((b: Policy) => {
if (filterPolicies === "") {
return true;
} else {
if (b.name.indexOf(filterPolicies) >= 0) {
return true;
} else {
return false;
}
}
})
.map(row => (
<TableRow key={row.name}>
<TableCell>{row.name}</TableCell>
<TableCell align="right">
<IconButton
aria-label="view"
onClick={() => {
this.setState({
addScreenOpen: true,
policyEdit: row
});
}}
>
<VisibilityIcon />
</IconButton>
<IconButton
aria-label="delete"
onClick={() => {
confirmDeletePolicy(row.name);
}}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
colSpan={3}
count={totalRecords}
rowsPerPage={rowsPerPage}
page={page}
SelectProps={{
inputProps: { "aria-label": "rows per page" },
native: true
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={MinTablePaginationActions}
/>
</TableRow>
</TableFooter>
</Table>
) : (
<div>No Policies</div>
)}
</Paper>
<TableWrapper
itemActions={tableActions}
columns={[{ label: "Name", elementKey: "name" }]}
isLoading={loading}
records={filteredRecords}
entityName="Policies"
idField="name"
paginatorConfig={{
rowsPerPageOptions: [5, 10, 25],
colSpan: 3,
count: totalRecords,
rowsPerPage: rowsPerPage,
page: page,
SelectProps: {
inputProps: { "aria-label": "rows per page" },
native: true
},
onChangePage: handleChangePage,
onChangeRowsPerPage: handleChangeRowsPerPage,
ActionsComponent: MinTablePaginationActions
}}
/>
</Grid>
</Grid>
</React.Fragment>

View File

@@ -164,7 +164,7 @@ class AddUserContent extends React.Component<
addLoading: false,
addError: "",
accessKey: res.accessKey,
selectedGroups: res.memberOf,
selectedGroups: res.memberOf || [],
enabled: res.status
});
})

View File

@@ -17,23 +17,17 @@
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import { LinearProgress } from "@material-ui/core";
import TableContainer from "@material-ui/core/TableContainer";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import Title from "../../../common/Title";
import InputAdornment from "@material-ui/core/InputAdornment";
import SearchIcon from "@material-ui/icons/Search";
import TextField from "@material-ui/core/TextField";
import Checkbox from "@material-ui/core/Checkbox";
import api from "../../../common/api";
import { groupsSort } from "../../../utils/sortFunctions";
import { GroupsList } from "../Groups/types";
import get from "lodash/get";
import TableWrapper from "../Common/TableWrapper/TableWrapper";
interface IGroupsProps {
classes: any;
@@ -196,40 +190,17 @@ const GroupsSelectors = ({
}}
/>
</Grid>
<TableContainer className={classes.tableContainer}>
<Table size="small" stickyHeader aria-label="sticky table">
<TableHead className={classes.minTableHeader}>
<TableRow>
<TableCell className={classes.stickyHeader}>
Select
</TableCell>
<TableCell className={classes.stickyHeader}>
Group
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredRecords.map(groupName => (
<TableRow key={`group-${groupName}`}>
<TableCell padding="checkbox">
<Checkbox
value={groupName}
color="primary"
inputProps={{
"aria-label": "secondary checkbox"
}}
onChange={selectionChanged}
checked={selGroups.includes(groupName)}
/>
</TableCell>
<TableCell className={classes.wrapCell}>
{groupName}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Grid item xs={12}>
<TableWrapper
columns={[{ label: "Group", elementKey: "" }]}
onSelect={selectionChanged}
selectedItems={selGroups}
isLoading={loading}
records={filteredRecords}
entityName="Groups"
idField=""
/>
</Grid>
</React.Fragment>
) : (
<div className={classes.noFound}>No Groups Available</div>

View File

@@ -128,19 +128,15 @@ class Users extends React.Component<IUsersProps, IUsersState> {
api
.invoke("GET", `/api/v1/users?offset=${offset}&limit=${rowsPerPage}`)
.then((res: UsersList) => {
const usersList = !res.users ? [] : res.users;
this.setState({
loading: false,
records: res.users.sort(usersSort),
records: usersList.sort(usersSort),
totalRecords: res.users.length,
error: ""
});
// if we get 0 results, and page > 0 , go down 1 page
if (
(res.users === undefined ||
res.users == null ||
res.users.length === 0) &&
page > 0
) {
if ((!usersList || res.users.length === 0) && page > 0) {
const newPage = page - 1;
this.setState({ page: newPage }, () => {
this.fetchRecords();