Skip to content

Commit

Permalink
Move change user password modal (#806)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinapurapu committed Jun 11, 2021
1 parent 8bea9ab commit 11d0080
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 22 deletions.
5 changes: 5 additions & 0 deletions portal-ui/src/screens/Console/Account/ChangePasswordModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ const ChangePassword = ({
return;
}

if (newPassword.length < 8) {
setModalErrorSnackMessage("Passwords must be at least 8 characters long");
return;
}

if (loading) {
return;
}
Expand Down
14 changes: 10 additions & 4 deletions portal-ui/src/screens/Console/Account/ChangeUserPasswordModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ const styles = (theme: Theme) =>
interface IChangeUserPasswordProps {
classes: any;
open: boolean;
selectedUser: User | null;
userName: string;
closeModal: () => void;
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
}

const ChangeUserPassword = ({
classes,
open,
selectedUser,
userName,
closeModal,
setModalErrorSnackMessage,
}: IChangeUserPasswordProps) => {
Expand All @@ -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,
};

Expand Down Expand Up @@ -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"
Expand Down
122 changes: 122 additions & 0 deletions portal-ui/src/screens/Console/Users/DeleteUserString.tsx
Original file line number Diff line number Diff line change
@@ -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);
16 changes: 0 additions & 16 deletions portal-ui/src/screens/Console/Users/ListUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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}>
Expand Down
97 changes: 95 additions & 2 deletions portal-ui/src/screens/Console/Users/UserDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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";
Expand All @@ -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({
Expand Down Expand Up @@ -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;
Expand All @@ -168,6 +187,7 @@ const UserDetails = ({ classes, match }: IUserDetailsProps) => {
}
setCurrentPolicies(currentPolicies);
setEnabled(res.status === "enabled");
setSelectedUser(res.user);
setLoading(false);
})
.catch((err) => {
Expand Down Expand Up @@ -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}`} />
Expand All @@ -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}>
Expand All @@ -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>
Expand Down

0 comments on commit 11d0080

Please sign in to comment.