Logout on Unauthorized. Fix all UI warnings. (#35)

This commit is contained in:
Daniel Valdivia
2020-04-06 16:35:30 -07:00
committed by GitHub
parent 31f0655ff6
commit 2001ab6dae
18 changed files with 215 additions and 232 deletions

File diff suppressed because one or more lines are too long

View File

@@ -24,7 +24,14 @@ export class API {
.set("Authorization", `Bearer ${token}`)
.send(data)
.then(res => res.body)
.catch(err => this.onError(err));
.catch(err => {
// if we get unauthorized, kick out the user
if (err.status === 401) {
storage.removeItem("token");
window.location.href = "/";
}
this.onError(err);
});
}
onError(err: any) {
@@ -38,5 +45,6 @@ export class API {
}
}
}
const api = new API();
export default api;

View File

@@ -35,9 +35,8 @@ import { AppState } from "../../../store";
import { setMenuOpen } from "../../../actions";
import { ThemedComponentProps } from "@material-ui/core/styles/withTheme";
import NotFoundPage from "../../NotFoundPage";
import BucketList from "./ListBuckets/ListBuckets";
import ViewBucket from "./ViewBucket/ViewBucket";
import ListBuckets from "./ListBuckets/ListBuckets";
import ViewBucket from "./ViewBucket/ViewBucket";
const styles = (theme: Theme) =>
createStyles({

View File

@@ -38,7 +38,7 @@ import TableCell from "@material-ui/core/TableCell";
import TableBody from "@material-ui/core/TableBody";
import Checkbox from "@material-ui/core/Checkbox";
import Table from "@material-ui/core/Table";
import { ArnList, BucketEventList } from "../types";
import { ArnList } from "../types";
const styles = (theme: Theme) =>
createStyles({
@@ -156,26 +156,6 @@ class AddEvent extends React.Component<IAddEventProps, IAddEventState> {
{ label: "DELETE - Object Deleted", value: "delete" }
];
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const targetD = e.target;
const value = targetD.value;
const checked = targetD.checked;
let elements: string[] = [...selectedEvents]; // We clone the selectedGroups array
if (checked) {
// If the user has checked this field we need to push this to selectedGroupsList
elements.push(value);
} else {
// User has unchecked this field, we need to remove it from the list
elements = elements.filter(element => element !== value);
}
this.setState({ selectedEvents: selectedEvents });
return elements;
};
const handleClick = (
event: React.MouseEvent<unknown> | ChangeEvent<unknown>,
name: string

View File

@@ -97,7 +97,7 @@ class DeleteEvent extends React.Component<
}
render() {
const { classes, deleteOpen, selectedBucket } = this.props;
const { classes, deleteOpen } = this.props;
const { deleteLoading, deleteError } = this.state;
return (

View File

@@ -26,8 +26,7 @@ import {
InputLabel,
LinearProgress,
MenuItem,
Select,
TextField
Select
} from "@material-ui/core";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import api from "../../../../common/api";

View File

@@ -35,7 +35,6 @@ import {
import Typography from "@material-ui/core/Typography";
import DeleteIcon from "@material-ui/icons/Delete";
import SetAccessPolicy from "./SetAccessPolicy";
import DeleteBucket from "../ListBuckets/DeleteBucket";
import { MinTablePaginationActions } from "../../../../common/MinTablePaginationActions";
import { CreateIcon } from "../../../../icons";
import AddEvent from "./AddEvent";
@@ -130,7 +129,7 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
fetchEvents() {
this.setState({ loading: true }, () => {
const { page, rowsPerPage } = this.state;
const { page } = this.state;
const { match } = this.props;
const bucketName = match.params["bucketName"];
api
@@ -205,7 +204,6 @@ class ViewBucket extends React.Component<IViewBucketProps, IViewBucketState> {
rowsPerPage,
deleteOpen,
addScreenOpen,
selectedBucket,
selectedEvent
} = this.state;

View File

@@ -170,7 +170,6 @@ class Console extends React.Component<
ConsoleProps & RouteComponentProps & StyledProps & ThemedComponentProps
> {
componentDidMount(): void {
//TODO: verify the session is still valid
api
.invoke("GET", `/api/v1/session`)
.then(res => {

View File

@@ -137,7 +137,7 @@ const Dashboard = ({ classes }: IDashboardProps) => {
});
};
const prettyUsage = (usage: string | undefined) => {
if (usage == undefined) {
if (usage === undefined) {
return "0";
}
return niceBytes(usage);
@@ -156,7 +156,7 @@ const Dashboard = ({ classes }: IDashboardProps) => {
return n.toFixed(n < 10 && l > 0 ? 1 : 0) + " " + units[l];
};
const prettyNumber = (usage: number | undefined) => {
if (usage == undefined) {
if (usage === undefined) {
return 0;
}
@@ -165,11 +165,12 @@ const Dashboard = ({ classes }: IDashboardProps) => {
return (
<React.Fragment>
<Grid container xs={12}>
<Grid container xs={12} spacing={3} className={classes.container}>
<Grid container xs={12}>
<Grid container>
<Grid container spacing={3} className={classes.container}>
<Grid container>
<Typography variant="h2">MinIO Console</Typography>
</Grid>
{error !== "" && <Grid container>{error}</Grid>}
<Grid item xs={12} md={4} lg={4}>
<Paper className={fixedHeightPaper}>
<Grid container direction="row" alignItems="center">

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, { useState, useEffect } from "react";
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import {
Button,
@@ -31,8 +31,6 @@ import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import api from "../../../common/api";
import UsersSelectors from "./UsersSelectors";
import { GroupsList } from "./types";
import { groupsSort } from "../../../utils/sortFunctions";
import Title from "../../../common/Title";
interface IGroupProps {
@@ -87,15 +85,69 @@ const AddGroup = ({
useEffect(() => {
if (saving) {
const saveRecord = () => {
if (selectedGroup !== null) {
api
.invoke("PUT", `/api/v1/groups/${groupName}`, {
group: groupName,
members: selectedUsers,
status: groupEnabled
})
.then(res => {
isSaving(false);
setError("");
closeModalAndRefresh();
})
.catch(err => {
isSaving(false);
setError(err);
});
} else {
api
.invoke("POST", "/api/v1/groups", {
group: groupName,
members: selectedUsers
})
.then(res => {
isSaving(false);
setError("");
closeModalAndRefresh();
})
.catch(err => {
isSaving(false);
setError(err);
});
}
};
saveRecord();
}
}, [saving]);
}, [
saving,
groupName,
selectedUsers,
groupEnabled,
selectedGroup,
closeModalAndRefresh
]);
useEffect(() => {
if (selectedGroup && loadingGroup) {
const fetchGroupInfo = () => {
api
.invoke("GET", `/api/v1/groups/${selectedGroup}`)
.then((res: MainGroupProps) => {
setGroupEnabled(res.status);
setGroupName(res.name);
setSelectedUsers(res.members);
})
.catch(err => {
setError(err);
isLoadingGroup(false);
});
};
fetchGroupInfo();
}
}, [loadingGroup]);
}, [loadingGroup, selectedGroup]);
//Fetch Actions
const setSaving = (event: React.FormEvent) => {
@@ -104,55 +156,6 @@ const AddGroup = ({
isSaving(true);
};
const saveRecord = () => {
if (selectedGroup !== null) {
api
.invoke("PUT", `/api/v1/groups/${groupName}`, {
group: groupName,
members: selectedUsers,
status: groupEnabled
})
.then(res => {
isSaving(false);
setError("");
closeModalAndRefresh();
})
.catch(err => {
isSaving(false);
setError(err);
});
} else {
api
.invoke("POST", "/api/v1/groups", {
group: groupName,
members: selectedUsers
})
.then(res => {
isSaving(false);
setError("");
closeModalAndRefresh();
})
.catch(err => {
isSaving(false);
setError(err);
});
}
};
const fetchGroupInfo = () => {
api
.invoke("GET", `/api/v1/groups/${selectedGroup}`)
.then((res: MainGroupProps) => {
setGroupEnabled(res.status);
setGroupName(res.name);
setSelectedUsers(res.members);
})
.catch(err => {
setError(err);
isLoadingGroup(false);
});
};
return (
<Dialog
open={open}

View File

@@ -54,28 +54,27 @@ const DeleteGroup = ({
useEffect(() => {
if (isDeleting) {
const removeRecord = () => {
if (!selectedGroup) {
return;
}
api
.invoke("DELETE", `/api/v1/groups/${selectedGroup}`)
.then((res: UsersList) => {
setDeleteLoading(false);
setError("");
closeDeleteModalAndRefresh(true);
})
.catch(err => {
setDeleteLoading(false);
setError(err);
});
};
removeRecord();
}
}, [isDeleting]);
const removeRecord = () => {
if (!selectedGroup) {
return;
}
api
.invoke("DELETE", `/api/v1/groups/${selectedGroup}`)
.then((res: UsersList) => {
setDeleteLoading(false);
setError("");
closeDeleteModalAndRefresh(true);
})
.catch(err => {
setDeleteLoading(false);
setError(err);
});
};
}, [isDeleting, selectedGroup, closeDeleteModalAndRefresh]);
const closeNoAction = () => {
setError("");

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, { useState, useEffect } from "react";
import React, { useEffect, useState } from "react";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
@@ -34,15 +34,13 @@ 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 Checkbox from "@material-ui/core/Checkbox";
import ViewIcon from "@material-ui/icons/Visibility";
import DeleteIcon from "@material-ui/icons/Delete";
import { CreateIcon } from "../../../icons";
import api from "../../../common/api";
import { MinTablePaginationActions } from "../../../common/MinTablePaginationActions";
import { GroupsList } from "./types";
import { groupsSort, usersSort } from "../../../utils/sortFunctions";
import { UsersList } from "../Users/types";
import { groupsSort } from "../../../utils/sortFunctions";
import AddGroup from "../Groups/AddGroup";
import DeleteGroup from "./DeleteGroup";
@@ -134,31 +132,30 @@ const Groups = ({ classes }: IGroupsProps) => {
useEffect(() => {
if (loading) {
const fetchRecords = () => {
const offset = page * rowsPerPage;
api
.invoke("GET", `/api/v1/groups?offset=${offset}&limit=${rowsPerPage}`)
.then((res: GroupsList) => {
setRecords(res.groups.sort(groupsSort));
setTotalRecords(res.total);
setError("");
isLoading(false);
// if we get 0 results, and page > 0 , go down 1 page
if ((!res.groups || res.groups.length === 0) && page > 0) {
const newPage = page - 1;
setPage(newPage);
}
})
.catch(err => {
setError(err);
isLoading(false);
});
};
fetchRecords();
}
}, [loading]);
const fetchRecords = () => {
const offset = page * rowsPerPage;
api
.invoke("GET", `/api/v1/groups?offset=${offset}&limit=${rowsPerPage}`)
.then((res: GroupsList) => {
setRecords(res.groups.sort(groupsSort));
setTotalRecords(res.total);
setError("");
isLoading(false);
// if we get 0 results, and page > 0 , go down 1 page
if ((!res.groups || res.groups.length === 0) && page > 0) {
const newPage = page - 1;
setPage(newPage);
}
})
.catch(err => {
setError(err);
isLoading(false);
});
};
}, [loading, page, rowsPerPage]);
const closeAddModalAndRefresh = () => {
setGroupOpen(false);
@@ -200,6 +197,7 @@ const Groups = ({ classes }: IGroupsProps) => {
<Grid item xs={12}>
<br />
</Grid>
{error !== "" ? <Grid container>{error}</Grid> : <React.Fragment />}
<Grid item xs={12} className={classes.actionsTray}>
<TextField
placeholder="Search Groups"

View File

@@ -163,6 +163,7 @@ const UsersSelectors = ({
return (
<React.Fragment>
<Title>Members</Title>
{error !== "" ? <div>{error}</div> : <React.Fragment />}
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}

View File

@@ -40,13 +40,11 @@ import { MinTablePaginationActions } from "../../../common/MinTablePaginationAct
import EditIcon from "@material-ui/icons/Edit";
import Checkbox from "@material-ui/core/Checkbox";
import { CreateIcon } from "../../../icons";
import TextField from '@material-ui/core/TextField';
import InputBase from '@material-ui/core/InputBase';
import SearchIcon from '@material-ui/icons/Search';
import InputAdornment from '@material-ui/core/InputAdornment';
import TextField from "@material-ui/core/TextField";
import SearchIcon from "@material-ui/icons/Search";
import InputAdornment from "@material-ui/core/InputAdornment";
import PlayArrowRoundedIcon from "@material-ui/icons/PlayArrowRounded";
const styles = (theme: Theme) =>
createStyles({
seeMore: {
@@ -84,14 +82,14 @@ const styles = (theme: Theme) =>
actionsTray: {
textAlign: "right",
"& button": {
marginLeft: 10,
},
marginLeft: 10
}
},
searchField: {
background: "#FFFFFF",
padding: 12,
borderRadius: 5,
boxShadow: "0px 3px 6px #00000012",
boxShadow: "0px 3px 6px #00000012"
}
});
@@ -241,7 +239,6 @@ class Permissions extends React.Component<
return (
<React.Fragment>
<AddPermission
open={addScreenOpen}
selectedPermission={selectedPermission}
@@ -269,7 +266,7 @@ class Permissions extends React.Component<
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
)
}}
/>
<Button
@@ -324,7 +321,7 @@ class Permissions extends React.Component<
<Checkbox
value="secondary"
color="primary"
inputProps={{ 'aria-label': 'secondary checkbox' }}
inputProps={{ "aria-label": "secondary checkbox" }}
/>
</TableCell>
<TableCell className={classes.wrapCell}>

View File

@@ -31,8 +31,8 @@ import Title from "../../../common/Title";
import api from "../../../common/api";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css";
import PolicyBuilder from "./PolicyBuilder";
import { Policy } from "./types";
require("codemirror/mode/javascript/javascript");
const styles = (theme: Theme) =>
@@ -70,6 +70,7 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
policyName: "",
policyDefinition: ""
};
addRecord(event: React.FormEvent) {
event.preventDefault();
const { policyName, addLoading, policyDefinition } = this.state;
@@ -101,9 +102,10 @@ class AddPolicy extends React.Component<IAddPolicyProps, IAddPolicyState> {
});
});
}
render() {
const { classes, open, policyEdit } = this.props;
const { addLoading, addError, policyName, policyDefinition } = this.state;
const { addLoading, addError } = this.state;
return (
<Dialog
fullWidth

View File

@@ -35,8 +35,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 Moment from "react-moment";
import { PolicyList, Policy } from "./types";
import { Policy, PolicyList } from "./types";
import AddPolicy from "./AddPolicy";
import DeletePolicy from "./DeletePolicy";
import api from "../../../common/api";

View File

@@ -16,7 +16,6 @@
import React from "react";
import Grid from "@material-ui/core/Grid";
import Title from "../../../common/Title";
import Typography from "@material-ui/core/Typography";
import {
Button,
@@ -87,7 +86,7 @@ class AddUserContent extends React.Component<
saveRecord(event: React.FormEvent) {
event.preventDefault();
const { accessKey, addLoading, secretKey, selectedGroups } = this.state;
const { accessKey, addLoading, secretKey } = this.state;
const { selectedUser } = this.props;
if (addLoading) {
return;
@@ -97,7 +96,7 @@ class AddUserContent extends React.Component<
api
.invoke("PUT", `/api/v1/users/${selectedUser.accessKey}`, {
accessKey,
secretKey: secretKey != "" ? null : secretKey
secretKey: secretKey !== "" ? null : secretKey
})
.then(res => {
this.setState(
@@ -272,6 +271,7 @@ interface IAddUserState {}
class AddUser extends React.Component<IAddUserProps, IAddUserState> {
state: IAddUserState = {};
render() {
const { open } = this.props;
return (

View File

@@ -31,8 +31,7 @@ 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 { UsersList } from "./types";
import { groupsSort, usersSort } from "../../../utils/sortFunctions";
import { groupsSort } from "../../../utils/sortFunctions";
import { GroupsList } from "../Groups/types";
interface IGroupsProps {
@@ -168,6 +167,7 @@ const GroupsSelectors = ({
<Grid item xs={12}>
<Paper className={classes.paper}>
{loading && <LinearProgress />}
{error !== "" && <div>{error}</div>}
{records != null && records.length > 0 ? (
<React.Fragment>
<Grid item xs={12} className={classes.actionsTray}>