Move change user password modal (#806)
This commit is contained in:
@@ -66,6 +66,11 @@ const ChangePassword = ({
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
setModalErrorSnackMessage("Passwords must be at least 8 characters long");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ const styles = (theme: Theme) =>
|
||||
interface IChangeUserPasswordProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
selectedUser: User | null;
|
||||
userName: string;
|
||||
closeModal: () => void;
|
||||
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ interface IChangeUserPasswordProps {
|
||||
const ChangeUserPassword = ({
|
||||
classes,
|
||||
open,
|
||||
selectedUser,
|
||||
userName,
|
||||
closeModal,
|
||||
setModalErrorSnackMessage,
|
||||
}: IChangeUserPasswordProps) => {
|
||||
@@ -67,9 +67,15 @@ const ChangeUserPassword = ({
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
setModalErrorSnackMessage("Passwords must be at least 8 characters long");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let request: ChangeUserPasswordRequest = {
|
||||
selectedUser: String(selectedUser?.accessKey),
|
||||
selectedUser: userName,
|
||||
newSecretKey: newPassword,
|
||||
};
|
||||
|
||||
@@ -110,7 +116,7 @@ const ChangeUserPassword = ({
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<h3>Change password for {selectedUser?.accessKey}</h3>
|
||||
<h3>Change password for {userName}</h3>
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="new-password"
|
||||
|
||||
122
portal-ui/src/screens/Console/Users/DeleteUserString.tsx
Normal file
122
portal-ui/src/screens/Console/Users/DeleteUserString.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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 { connect } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
LinearProgress,
|
||||
} from "@material-ui/core";
|
||||
import api from "../../../common/api";
|
||||
import { User, UsersList } from "./types";
|
||||
import { setErrorSnackMessage } from "../../../actions";
|
||||
import history from "../../../history";
|
||||
|
||||
interface IDeleteUserProps {
|
||||
closeDeleteModalAndRefresh: (refresh: boolean) => void;
|
||||
deleteOpen: boolean;
|
||||
userName: string;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
}
|
||||
|
||||
const DeleteUserString = ({
|
||||
closeDeleteModalAndRefresh,
|
||||
deleteOpen,
|
||||
userName,
|
||||
setErrorSnackMessage,
|
||||
}: IDeleteUserProps) => {
|
||||
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
|
||||
|
||||
const removeRecord = () => {
|
||||
if (deleteLoading) {
|
||||
return;
|
||||
}
|
||||
if (userName == null) {
|
||||
return;
|
||||
}
|
||||
setDeleteLoading(true);
|
||||
api
|
||||
.invoke("DELETE", `/api/v1/users/${userName}`, {
|
||||
id: userName,
|
||||
})
|
||||
.then((res: UsersList) => {
|
||||
setDeleteLoading(false);
|
||||
closeDeleteModalAndRefresh(true);
|
||||
})
|
||||
.catch((err) => {
|
||||
setDeleteLoading(false);
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
};
|
||||
|
||||
if (userName === null) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={deleteOpen}
|
||||
onClose={() => {
|
||||
closeDeleteModalAndRefresh(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">Delete User</DialogTitle>
|
||||
<DialogContent>
|
||||
{deleteLoading && <LinearProgress />}
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Are you sure you want to delete user <b>{userName}</b>?
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
closeDeleteModalAndRefresh(false);
|
||||
}}
|
||||
color="primary"
|
||||
disabled={deleteLoading}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
removeRecord();
|
||||
closeDeleteModalAndRefresh(true);
|
||||
history.push(`/users/`);
|
||||
}}
|
||||
color="secondary"
|
||||
autoFocus
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setErrorSnackMessage,
|
||||
};
|
||||
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
|
||||
export default connector(DeleteUserString);
|
||||
@@ -37,7 +37,6 @@ import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import SetPolicy from "../Policies/SetPolicy";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import history from "../../../history";
|
||||
import ChangeUserPasswordModal from "../Account/ChangeUserPasswordModal";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -91,8 +90,6 @@ const ListUsers = ({ classes, setErrorSnackMessage }: IUsersProps) => {
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [checkedUsers, setCheckedUsers] = useState<string[]>([]);
|
||||
const [policyOpen, setPolicyOpen] = useState<boolean>(false);
|
||||
const [ChangeUserPasswordModalOpen, setChangeUserPasswordModalOpen] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const fetchRecords = useCallback(() => {
|
||||
setLoading(true);
|
||||
@@ -168,14 +165,8 @@ const ListUsers = ({ classes, setErrorSnackMessage }: IUsersProps) => {
|
||||
|
||||
const userLoggedIn = atob(localStorage.getItem("userLoggedIn") || "");
|
||||
|
||||
const setNewPW = (selectionElement: any): void => {
|
||||
setChangeUserPasswordModalOpen(true);
|
||||
setSelectedUser(selectionElement);
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{ type: "view", onClick: viewAction },
|
||||
{ type: "edit", onClick: setNewPW },
|
||||
{
|
||||
type: "delete",
|
||||
onClick: deleteAction,
|
||||
@@ -223,13 +214,6 @@ const ListUsers = ({ classes, setErrorSnackMessage }: IUsersProps) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{ChangeUserPasswordModalOpen && (
|
||||
<ChangeUserPasswordModal
|
||||
open={ChangeUserPasswordModalOpen}
|
||||
closeModal={() => setChangeUserPasswordModalOpen(false)}
|
||||
selectedUser={selectedUser}
|
||||
/>
|
||||
)}
|
||||
<PageHeader label={"Users"} />
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { Button, Grid } from "@material-ui/core";
|
||||
import { Button, Grid, IconButton, Menu, MenuItem } from "@material-ui/core";
|
||||
import PageHeader from "../Common/PageHeader/PageHeader";
|
||||
import { CreateIcon } from "../../../icons";
|
||||
import {
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
containerForHeader,
|
||||
searchField,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { IPolicyItem } from "./types";
|
||||
import { IPolicyItem, User, UsersList } from "./types";
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import { TabPanel } from "../../shared/tabs";
|
||||
@@ -42,6 +42,10 @@ import SetUserPolicies from "./SetUserPolicies";
|
||||
import { Bookmark } from "@material-ui/icons";
|
||||
import history from "../../../history";
|
||||
import UserServiceAccountsPanel from "./UserServiceAccountsPanel";
|
||||
import MoreVertIcon from "@material-ui/icons/MoreVert";
|
||||
import ChangeUserPasswordModal from "../Account/ChangeUserPasswordModal";
|
||||
import DeleteUserString from "./DeleteUserString";
|
||||
import { usersSort } from "../../../utils/sortFunctions";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -134,14 +138,29 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
||||
const [addGroupOpen, setAddGroupOpen] = useState<boolean>(false);
|
||||
const [policyOpen, setPolicyOpen] = useState<boolean>(false);
|
||||
const [addLoading, setAddLoading] = useState<boolean>(false);
|
||||
const [records, setRecords] = useState<User[]>([]);
|
||||
|
||||
const [enabled, setEnabled] = useState<boolean>(false);
|
||||
const [selectedGroups, setSelectedGroups] = useState<string[]>([]);
|
||||
const [currentGroups, setCurrentGroups] = useState<IGroupItem[]>([]);
|
||||
const [currentPolicies, setCurrentPolicies] = useState<IPolicyItem[]>([]);
|
||||
const [changeUserPasswordModalOpen, setChangeUserPasswordModalOpen] =
|
||||
useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedUser, setSelectedUser] = useState<User | null>(null);
|
||||
|
||||
const userName = match.params["userName"];
|
||||
|
||||
const changeUserPassword = () => {
|
||||
setAnchorEl(null);
|
||||
setChangeUserPasswordModalOpen(true);
|
||||
};
|
||||
|
||||
const deleteUser = () => {
|
||||
setAnchorEl(null);
|
||||
setDeleteOpen(true);
|
||||
};
|
||||
|
||||
const getUserInformation = useCallback(() => {
|
||||
if (userName === "") {
|
||||
return null;
|
||||
@@ -168,6 +187,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
||||
}
|
||||
setCurrentPolicies(currentPolicies);
|
||||
setEnabled(res.status === "enabled");
|
||||
setSelectedUser(res.user);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -196,12 +216,41 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
||||
});
|
||||
};
|
||||
|
||||
const fetchRecords = useCallback(() => {
|
||||
setLoading(true);
|
||||
api
|
||||
.invoke("GET", `/api/v1/users`)
|
||||
.then((res: UsersList) => {
|
||||
const users = res.users === null ? [] : res.users;
|
||||
|
||||
setLoading(false);
|
||||
setRecords(users.sort(usersSort));
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoading(false);
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
}, [setLoading, setRecords, setErrorSnackMessage]);
|
||||
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
|
||||
const handleUserMenu = (event: any) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getUserInformation();
|
||||
}, [getUserInformation]);
|
||||
|
||||
const userLoggedIn = atob(localStorage.getItem("userLoggedIn") || "");
|
||||
|
||||
const closeDeleteModalAndRefresh = (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
if (refresh) {
|
||||
fetchRecords();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PageHeader label={`User: ${userName}`} />
|
||||
@@ -226,6 +275,23 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{deleteOpen && (
|
||||
<DeleteUserString
|
||||
deleteOpen={deleteOpen}
|
||||
userName={userName}
|
||||
closeDeleteModalAndRefresh={(refresh: boolean) => {
|
||||
closeDeleteModalAndRefresh(refresh);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{changeUserPasswordModalOpen && (
|
||||
<ChangeUserPasswordModal
|
||||
open={changeUserPasswordModalOpen}
|
||||
userName={userName}
|
||||
closeModal={() => setChangeUserPasswordModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.container}>
|
||||
<Grid item xs={12}>
|
||||
@@ -249,10 +315,37 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Fragment>
|
||||
<IconButton
|
||||
aria-label="more"
|
||||
aria-controls="long-menu"
|
||||
aria-haspopup="true"
|
||||
onClick={handleUserMenu}
|
||||
>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="long-menu"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={Boolean(anchorEl)}
|
||||
>
|
||||
<MenuItem
|
||||
key="changeUserPassword"
|
||||
onClick={changeUserPassword}
|
||||
>
|
||||
Change User Password
|
||||
</MenuItem>
|
||||
<MenuItem key="deleteUser" onClick={deleteUser}>
|
||||
Delete User
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Fragment>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<h1>{selectedUser != null && selectedUser.id}</h1>
|
||||
<Grid item xs={12}>
|
||||
<br />
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user