Migrated Users Module components to mds (#2920)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -30,23 +30,20 @@ import {
|
||||
ServiceAccountIcon,
|
||||
} from "mds";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import AddServiceAccountHelpBox from "./AddServiceAccountHelpBox";
|
||||
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
|
||||
import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import { getRandomString } from "../../../common/utils";
|
||||
import { api } from "api";
|
||||
import { errorToHandler } from "api/errors";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import { ContentType } from "api/consoleApi";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import AddServiceAccountHelpBox from "./AddServiceAccountHelpBox";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
|
||||
const AddServiceAccount = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -123,7 +120,7 @@ const AddServiceAccount = () => {
|
||||
{newServiceAccount !== null && (
|
||||
<CredentialsPrompt
|
||||
newServiceAccount={newServiceAccount}
|
||||
open={newServiceAccount !== null}
|
||||
open={true}
|
||||
closeModal={() => {
|
||||
closeCredentialsModal();
|
||||
}}
|
||||
|
||||
@@ -15,47 +15,23 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Button, ChangePasswordIcon } from "mds";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { Box, Button, ChangePasswordIcon, FormLayout, InputBox } from "mds";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import {
|
||||
containerForHeader,
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
spacingUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import { api } from "api";
|
||||
import { ChangeUserPasswordRequest } from "api/consoleApi";
|
||||
import { errorToHandler } from "api/errors";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
buttonContainer: {
|
||||
textAlign: "right",
|
||||
},
|
||||
...modalStyleUtils,
|
||||
...formFieldStyles,
|
||||
...spacingUtils,
|
||||
...containerForHeader,
|
||||
});
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
|
||||
interface IChangeUserPasswordProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
userName: string;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const ChangeUserPassword = ({
|
||||
classes,
|
||||
open,
|
||||
userName,
|
||||
closeModal,
|
||||
@@ -123,37 +99,31 @@ const ChangeUserPassword = ({
|
||||
changeUserPassword(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.modalFormScrollable}>
|
||||
<div className={classes.spacerBottom}>
|
||||
Change password for: {userName}
|
||||
</div>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="new-password"
|
||||
name="new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setNewPassword(event.target.value);
|
||||
}}
|
||||
label="New Password"
|
||||
type="password"
|
||||
value={newPassword}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="re-new-password"
|
||||
name="re-new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setReNewPassword(event.target.value);
|
||||
}}
|
||||
label="Type New Password Again"
|
||||
type="password"
|
||||
value={reNewPassword}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<Box sx={{ margin: "10px 0 20px" }}>
|
||||
Change password for: <strong>{userName}</strong>
|
||||
</Box>
|
||||
<InputBox
|
||||
id="new-password"
|
||||
name="new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setNewPassword(event.target.value);
|
||||
}}
|
||||
label="New Password"
|
||||
type="password"
|
||||
value={newPassword}
|
||||
/>
|
||||
<InputBox
|
||||
id="re-new-password"
|
||||
name="re-new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setReNewPassword(event.target.value);
|
||||
}}
|
||||
label="Type New Password Again"
|
||||
type="password"
|
||||
value={reNewPassword}
|
||||
/>
|
||||
<Box sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"save-user-password"}
|
||||
type="submit"
|
||||
@@ -165,16 +135,16 @@ const ChangeUserPassword = ({
|
||||
}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
{loading && (
|
||||
<Grid item xs={12}>
|
||||
<Box>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
</FormLayout>
|
||||
</form>
|
||||
</ModalWrapper>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ChangeUserPassword);
|
||||
export default ChangeUserPassword;
|
||||
|
||||
@@ -714,33 +714,6 @@ export const commonDashboardInfocard: any = {
|
||||
},
|
||||
};
|
||||
|
||||
export const serviceAccountStyles: any = {
|
||||
buttonContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
codeMirrorContainer: {
|
||||
marginBottom: 20,
|
||||
paddingLeft: 15,
|
||||
"& label": {
|
||||
marginBottom: ".5rem",
|
||||
},
|
||||
"& label + div": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
stackedInputs: {
|
||||
display: "flex",
|
||||
gap: 15,
|
||||
paddingBottom: "1rem",
|
||||
paddingLeft: "1rem",
|
||||
flexFlow: "column",
|
||||
},
|
||||
buttonSpacer: {
|
||||
marginRight: "1rem",
|
||||
},
|
||||
};
|
||||
|
||||
export const tableStyles: any = {
|
||||
tableBlock: {
|
||||
display: "flex",
|
||||
|
||||
@@ -24,6 +24,7 @@ type SearchBoxProps = {
|
||||
onChange: (value: string) => void;
|
||||
overrideClass?: any;
|
||||
id?: string;
|
||||
label?: string;
|
||||
sx?: CSSObject;
|
||||
};
|
||||
|
||||
@@ -33,6 +34,7 @@ const SearchBox = ({
|
||||
overrideClass,
|
||||
value,
|
||||
id = "search-resource",
|
||||
label = "",
|
||||
sx,
|
||||
}: SearchBoxProps) => {
|
||||
return (
|
||||
@@ -40,7 +42,7 @@ const SearchBox = ({
|
||||
placeholder={placeholder}
|
||||
className={overrideClass ? overrideClass : ""}
|
||||
id={id}
|
||||
label=""
|
||||
label={label}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
|
||||
@@ -14,23 +14,11 @@
|
||||
// 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 { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { DataTable, Grid, Box } from "mds";
|
||||
import { policySort } from "../../../utils/sortFunctions";
|
||||
import {
|
||||
actionsTray,
|
||||
searchField,
|
||||
selectorsCommon,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
@@ -38,49 +26,17 @@ import { setSelectedPolicies } from "../Users/AddUsersSlice";
|
||||
import { useSelector } from "react-redux";
|
||||
import { api } from "../../../api";
|
||||
import {
|
||||
Error,
|
||||
HttpResponse,
|
||||
ListPoliciesResponse,
|
||||
Error,
|
||||
} from "../../../api/consoleApi";
|
||||
|
||||
interface ISelectPolicyProps {
|
||||
classes: any;
|
||||
selectedPolicy?: string[];
|
||||
noTitle?: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
noFound: {
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
},
|
||||
searchBox: {
|
||||
flex: 1,
|
||||
},
|
||||
fieldLabel: {
|
||||
fontWeight: 400,
|
||||
width: 160,
|
||||
marginRight: 10,
|
||||
},
|
||||
tableBlock: {
|
||||
...tableStyles.tableBlock,
|
||||
},
|
||||
filterBox: {
|
||||
display: "flex",
|
||||
marginBottom: 15,
|
||||
alignItems: "center",
|
||||
"& span": {
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
...searchField,
|
||||
...tableStyles,
|
||||
...actionsTray,
|
||||
...selectorsCommon,
|
||||
});
|
||||
|
||||
const PolicySelectors = ({ classes, noTitle = false }: ISelectPolicyProps) => {
|
||||
const PolicySelectors = ({ noTitle = false }: ISelectPolicyProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
// Local State
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
@@ -143,49 +99,44 @@ const PolicySelectors = ({ classes, noTitle = false }: ISelectPolicyProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
{loading && <LinearProgress />}
|
||||
{records.length > 0 ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.filterBox}>
|
||||
{!noTitle && (
|
||||
<span className={classes.fieldLabel}>Assign Policies</span>
|
||||
)}
|
||||
<div className={classes.searchBox}>
|
||||
<SearchBox
|
||||
placeholder="Start typing to search for a Policy"
|
||||
onChange={(value) => {
|
||||
setFilter(value);
|
||||
}}
|
||||
value={filter}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={classes.tableBlock}
|
||||
style={{ paddingBottom: 16 }}
|
||||
>
|
||||
<TableWrapper
|
||||
columns={[{ label: "Policy", elementKey: "name" }]}
|
||||
onSelect={selectionChanged}
|
||||
selectedItems={currentPolicies}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Policies"
|
||||
idField="name"
|
||||
customPaperHeight={classes.multiSelectTable}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<div className={classes.noFound}>No Policies Available</div>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={"inputItem"}>
|
||||
{loading && <LinearProgress />}
|
||||
{records.length > 0 ? (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={"inputItem"}>
|
||||
<SearchBox
|
||||
placeholder="Start typing to search for a Policy"
|
||||
onChange={(value) => {
|
||||
setFilter(value);
|
||||
}}
|
||||
value={filter}
|
||||
label={!noTitle ? "Assign Policies" : ""}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<DataTable
|
||||
columns={[{ label: "Policy", elementKey: "name" }]}
|
||||
onSelect={selectionChanged}
|
||||
selectedItems={currentPolicies}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Policies"
|
||||
idField="name"
|
||||
customPaperHeight={"200px"}
|
||||
/>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
}}
|
||||
>
|
||||
No Policies Available
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(PolicySelectors);
|
||||
export default PolicySelectors;
|
||||
|
||||
@@ -15,27 +15,19 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { BackLink, Button, CreateUserIcon, FormLayout, PageLayout } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import UserSelector from "./UserSelector";
|
||||
import PasswordSelector from "./PasswordSelector";
|
||||
import { createUserAsync, resetFormAsync } from "./thunk/AddUsersThunk";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
BackLink,
|
||||
Button,
|
||||
CreateUserIcon,
|
||||
FormLayout,
|
||||
Grid,
|
||||
PageLayout,
|
||||
} from "mds";
|
||||
import { createUserAsync, resetFormAsync } from "./thunk/AddUsersThunk";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
|
||||
import PolicySelectors from "../Policies/PolicySelectors";
|
||||
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import AddUserHelpBox from "./AddUserHelpBox";
|
||||
import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import { useSelector } from "react-redux";
|
||||
@@ -44,20 +36,15 @@ import {
|
||||
setSelectedGroups,
|
||||
setSendEnabled,
|
||||
} from "./AddUsersSlice";
|
||||
import AddUserHelpBox from "./AddUserHelpBox";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import PolicySelectors from "../Policies/PolicySelectors";
|
||||
import UserSelector from "./UserSelector";
|
||||
import PasswordSelector from "./PasswordSelector";
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
|
||||
interface IAddUserProps {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
|
||||
const AddUser = ({ classes }: IAddUserProps) => {
|
||||
const AddUser = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selectedPolicies = useSelector(
|
||||
(state: AppState) => state.createUser.selectedPolicies
|
||||
@@ -128,55 +115,40 @@ const AddUser = ({ classes }: IAddUserProps) => {
|
||||
saveRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<UserSelector />
|
||||
<PasswordSelector />
|
||||
<PolicySelectors selectedPolicy={selectedPolicies} />
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={(elements: string[]) => {
|
||||
dispatch(setSelectedGroups(elements));
|
||||
}}
|
||||
/>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.formFieldRow}>
|
||||
<UserSelector classes={classes} />
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.formFieldRow}>
|
||||
<PasswordSelector classes={classes} />
|
||||
</div>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid item xs={12}>
|
||||
<PolicySelectors selectedPolicy={selectedPolicies} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={(elements: string[]) => {
|
||||
dispatch(setSelectedGroups(elements));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-add-user"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={(e) => {
|
||||
dispatch(resetFormAsync());
|
||||
}}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-add-user"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={(e) => {
|
||||
dispatch(resetFormAsync());
|
||||
}}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
id={"save-user"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
<Button
|
||||
id={"save-user"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
</form>
|
||||
</FormLayout>
|
||||
@@ -186,4 +158,4 @@ const AddUser = ({ classes }: IAddUserProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddUser);
|
||||
export default AddUser;
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// 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, { Fragment } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
modalStyleUtils,
|
||||
serviceAccountStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...serviceAccountStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
|
||||
interface IAddUserServiceAccountProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
user: string;
|
||||
closeModalAndRefresh: (res: NewServiceAccount | null) => void;
|
||||
}
|
||||
|
||||
const AddUserServiceAccount = ({
|
||||
classes,
|
||||
open,
|
||||
closeModalAndRefresh,
|
||||
user,
|
||||
}: IAddUserServiceAccountProps) => {
|
||||
return <Fragment />;
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddUserServiceAccount);
|
||||
@@ -15,39 +15,24 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import {
|
||||
BackLink,
|
||||
Box,
|
||||
Button,
|
||||
IAMPoliciesIcon,
|
||||
FormLayout,
|
||||
Grid,
|
||||
InputBox,
|
||||
PageLayout,
|
||||
PasswordKeyIcon,
|
||||
ServiceAccountCredentialsIcon,
|
||||
ServiceAccountIcon,
|
||||
Switch,
|
||||
} from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { Box } from "@mui/material";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
|
||||
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import { ErrorResponseHandler } from "../../../../src/common/types";
|
||||
import api from "../../../../src/common/api";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import SectionTitle from "../Common/SectionTitle";
|
||||
|
||||
import AddUserServiceAccountHelpBox from "./AddUserServiceAccountHelpBox";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import {
|
||||
decodeURLString,
|
||||
encodeURLString,
|
||||
@@ -55,20 +40,15 @@ import {
|
||||
} from "../../../common/utils";
|
||||
import { setErrorSnackMessage, setHelpName } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import api from "../../../../src/common/api";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import AddUserServiceAccountHelpBox from "./AddUserServiceAccountHelpBox";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
|
||||
interface IAddServiceAccountProps {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
|
||||
const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
const AddServiceAccount = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
@@ -80,7 +60,6 @@ const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
useState<boolean>(false);
|
||||
const [newServiceAccount, setNewServiceAccount] =
|
||||
useState<NewServiceAccount | null>(null);
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||
const [policyJSON, setPolicyJSON] = useState<string>("");
|
||||
|
||||
const userName = decodeURLString(params.userName || "");
|
||||
@@ -145,7 +124,6 @@ const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
setNewServiceAccount(null);
|
||||
setAccessKey("");
|
||||
setSecretKey("");
|
||||
setShowPassword(false);
|
||||
};
|
||||
|
||||
const closeCredentialsModal = () => {
|
||||
@@ -183,152 +161,97 @@ const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
actions={<HelpMenu />}
|
||||
/>
|
||||
<PageLayout>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
padding: "25px",
|
||||
gap: "25px",
|
||||
gridTemplateColumns: {
|
||||
md: "2fr 1.2fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
border: "1px solid #eaeaea",
|
||||
}}
|
||||
<FormLayout
|
||||
helpBox={<AddUserServiceAccountHelpBox />}
|
||||
icon={<ServiceAccountCredentialsIcon />}
|
||||
title={`Create Access Key for ${userName}`}
|
||||
>
|
||||
<Box>
|
||||
<SectionTitle icon={<ServiceAccountCredentialsIcon />}>
|
||||
{`Create Access Key for ${userName}`}
|
||||
</SectionTitle>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addUserServiceAccount(e);
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
addUserServiceAccount(e);
|
||||
}}
|
||||
>
|
||||
<InputBox
|
||||
value={accessKey}
|
||||
label={"Access Key"}
|
||||
id={"accessKey"}
|
||||
name={"accessKey"}
|
||||
placeholder={"Enter Access Key"}
|
||||
onChange={(e) => {
|
||||
setAccessKey(e.target.value);
|
||||
}}
|
||||
>
|
||||
<Grid container item spacing="20" sx={{ marginTop: 1 }}>
|
||||
<Grid item xs={12}>
|
||||
<Grid container item spacing="20">
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={1}>
|
||||
<PasswordKeyIcon />
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Grid container item spacing="20">
|
||||
<Grid item xs={12}>
|
||||
{" "}
|
||||
<div className={classes.stackedInputs}>
|
||||
<InputBoxWrapper
|
||||
value={accessKey}
|
||||
label={"Access Key"}
|
||||
id={"accessKey"}
|
||||
name={"accessKey"}
|
||||
placeholder={"Enter Access Key"}
|
||||
onChange={(e) => {
|
||||
setAccessKey(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.stackedInputs}>
|
||||
<InputBoxWrapper
|
||||
value={secretKey}
|
||||
label={"Secret Key"}
|
||||
id={"secretKey"}
|
||||
name={"secretKey"}
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder={"Enter Secret Key"}
|
||||
onChange={(e) => {
|
||||
setSecretKey(e.target.value);
|
||||
}}
|
||||
overlayIcon={
|
||||
showPassword ? (
|
||||
<VisibilityOffIcon />
|
||||
) : (
|
||||
<RemoveRedEyeIcon />
|
||||
)
|
||||
}
|
||||
overlayAction={() =>
|
||||
setShowPassword(!showPassword)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container item spacing="20">
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={1}>
|
||||
<IAMPoliciesIcon />
|
||||
</Grid>
|
||||
<Grid item xs={11}>
|
||||
<FormSwitchWrapper
|
||||
value="serviceAccountPolicy"
|
||||
id="serviceAccountPolicy"
|
||||
name="serviceAccountPolicy"
|
||||
checked={isRestrictedByPolicy}
|
||||
onChange={(
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
setIsRestrictedByPolicy(event.target.checked);
|
||||
}}
|
||||
label={"Restrict beyond user policy"}
|
||||
tooltip={
|
||||
"You can specify an optional JSON-formatted IAM policy to further restrict Access Key access to a subset of the actions and resources explicitly allowed for the parent user. Additional access beyond that of the parent user cannot be implemented through these policies."
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{isRestrictedByPolicy && (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={classes.codeMirrorContainer}
|
||||
>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<CodeMirrorWrapper
|
||||
label={"Policy"}
|
||||
value={policyJSON}
|
||||
onChange={(value) => {
|
||||
setPolicyJSON(value);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-add-sa"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
<Button
|
||||
id="create-sa"
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
label={"Create"}
|
||||
startIcon={<ServiceAccountIcon />}
|
||||
/>
|
||||
<InputBox
|
||||
value={secretKey}
|
||||
label={"Secret Key"}
|
||||
id={"secretKey"}
|
||||
name={"secretKey"}
|
||||
type={"password"}
|
||||
placeholder={"Enter Secret Key"}
|
||||
onChange={(e) => {
|
||||
setSecretKey(e.target.value);
|
||||
}}
|
||||
startIcon={<PasswordKeyIcon />}
|
||||
/>
|
||||
<Switch
|
||||
value="serviceAccountPolicy"
|
||||
id="serviceAccountPolicy"
|
||||
name="serviceAccountPolicy"
|
||||
checked={isRestrictedByPolicy}
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsRestrictedByPolicy(event.target.checked);
|
||||
}}
|
||||
label={"Restrict beyond user policy"}
|
||||
description={
|
||||
"You can specify an optional JSON-formatted IAM policy to further restrict Access Key access to a subset of the actions and resources explicitly allowed for the parent user. Additional access beyond that of the parent user cannot be implemented through these policies."
|
||||
}
|
||||
/>
|
||||
{isRestrictedByPolicy && (
|
||||
<Grid item xs={12}>
|
||||
<Box>
|
||||
<PanelTitle>
|
||||
Current User Policy - edit the JSON to remove permissions
|
||||
for this Access Key
|
||||
</PanelTitle>
|
||||
</Box>
|
||||
<Grid item xs={12} sx={{ ...modalStyleUtils.formScrollable }}>
|
||||
<CodeMirrorWrapper
|
||||
value={policyJSON}
|
||||
onChange={(value) => {
|
||||
setPolicyJSON(value);
|
||||
}}
|
||||
editorHeight={"350px"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Box>
|
||||
<AddUserServiceAccountHelpBox />
|
||||
</Box>
|
||||
)}
|
||||
<Grid item xs={12} sx={{ ...modalStyleUtils.modalButtonBar }}>
|
||||
<Button
|
||||
id={"clear"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
id={"create-sa"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
label={"Create"}
|
||||
/>
|
||||
</Grid>
|
||||
</form>
|
||||
</FormLayout>
|
||||
</PageLayout>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(AddServiceAccount);
|
||||
export default AddServiceAccount;
|
||||
|
||||
@@ -15,21 +15,13 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { AddMembersToGroupIcon, Button } from "mds";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { AddMembersToGroupIcon, Button, FormLayout, Grid, ReadBox } from "mds";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import api from "../../../common/api";
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import PredefinedList from "../Common/FormComponents/PredefinedList/PredefinedList";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
@@ -37,20 +29,12 @@ interface IAddToGroup {
|
||||
open: boolean;
|
||||
checkedUsers: any;
|
||||
closeModalAndRefresh: any;
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalStyleUtils,
|
||||
...formFieldStyles,
|
||||
});
|
||||
|
||||
const BulkAddToGroup = ({
|
||||
open,
|
||||
checkedUsers,
|
||||
closeModalAndRefresh,
|
||||
classes,
|
||||
}: IAddToGroup) => {
|
||||
const dispatch = useAppDispatch();
|
||||
//Local States
|
||||
@@ -120,61 +104,57 @@ const BulkAddToGroup = ({
|
||||
>
|
||||
{accepted ? (
|
||||
<React.Fragment>
|
||||
<Grid container>
|
||||
<PredefinedList
|
||||
label={"Groups"}
|
||||
content={selectedGroups.join(", ")}
|
||||
/>
|
||||
<PredefinedList label={"Users"} content={checkedUsers.join(", ")} />
|
||||
</Grid>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<FormLayout
|
||||
withBorders={false}
|
||||
containerPadding={false}
|
||||
sx={{ margin: "30px 0" }}
|
||||
>
|
||||
<ReadBox label={"Groups"} sx={{ width: "100%" }}>
|
||||
{selectedGroups.join(", ")}
|
||||
</ReadBox>
|
||||
<ReadBox label={"Users"} sx={{ width: "100%" }}>
|
||||
{" "}
|
||||
{checkedUsers.join(", ")}{" "}
|
||||
</ReadBox>
|
||||
</FormLayout>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<form noValidate autoComplete="off" onSubmit={setSaving}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.modalFormScrollable}>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<PredefinedList
|
||||
label={"Selected Users"}
|
||||
content={checkedUsers.join(", ")}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={setSelectedGroups}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-bulk-add-group"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
color="primary"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
<Button
|
||||
id={"save-add-group"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
disabled={saving || selectedGroups.length < 1}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
{saving && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<ReadBox label={"Selected Users"} sx={{ width: "100%" }}>
|
||||
{checkedUsers.join(", ")}
|
||||
</ReadBox>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={setSelectedGroups}
|
||||
/>
|
||||
</FormLayout>
|
||||
<Grid item xs={12} sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-bulk-add-group"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
color="primary"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
<Button
|
||||
id={"save-add-group"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
disabled={saving || selectedGroups.length < 1}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
{saving && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</form>
|
||||
)}
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(BulkAddToGroup);
|
||||
export default BulkAddToGroup;
|
||||
|
||||
@@ -14,41 +14,25 @@
|
||||
// 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 Grid from "@mui/material/Grid";
|
||||
import React, { useCallback, useEffect, useState, Fragment } from "react";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { AddMembersToGroupIcon, Button } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
modalBasic,
|
||||
spacingUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { AddMembersToGroupIcon, Button, FormLayout, Grid, Box } from "mds";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import api from "../../../common/api";
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import { encodeURLString } from "../../../common/utils";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...spacingUtils,
|
||||
...modalBasic,
|
||||
});
|
||||
import api from "../../../common/api";
|
||||
import GroupsSelectors from "./GroupsSelectors";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
|
||||
interface IChangeUserGroupsContentProps {
|
||||
classes: any;
|
||||
closeModalAndRefresh: () => void;
|
||||
selectedUser: string;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
const ChangeUserGroups = ({
|
||||
classes,
|
||||
closeModalAndRefresh,
|
||||
selectedUser,
|
||||
open,
|
||||
@@ -151,7 +135,7 @@ const ChangeUserGroups = ({
|
||||
title={"Set Groups"}
|
||||
titleIcon={<AddMembersToGroupIcon />}
|
||||
>
|
||||
<React.Fragment>
|
||||
<Fragment>
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
@@ -159,50 +143,40 @@ const ChangeUserGroups = ({
|
||||
saveRecord(e);
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={(elements: string[]) => {
|
||||
setSelectedGroups(elements);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: 2,
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
width: "100%",
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<GroupsSelectors
|
||||
selectedGroups={selectedGroups}
|
||||
setSelectedGroups={(elements: string[]) => {
|
||||
setSelectedGroups(elements);
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
id={"clear-change-user-groups"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
/>
|
||||
</FormLayout>
|
||||
<Box sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear-change-user-groups"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
id={"save-user-groups"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Box>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Button
|
||||
id={"save-user-groups"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
disabled={addLoading || !sendEnabled}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Box>
|
||||
{addLoading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
</Grid>
|
||||
)}
|
||||
</form>
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ChangeUserGroups);
|
||||
export default ChangeUserGroups;
|
||||
|
||||
@@ -15,37 +15,35 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { DialogContentText } from "@mui/material";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { setErrorSnackMessage } from "../../../systemSlice";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import { ConfirmDeleteIcon, Loader } from "mds";
|
||||
import { ConfirmDeleteIcon, Loader, DataTable } from "mds";
|
||||
import { encodeURLString } from "../../../common/utils";
|
||||
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
|
||||
import useApi from "../Common/Hooks/useApi";
|
||||
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
|
||||
import WarningMessage from "../Common/WarningMessage/WarningMessage";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import api from "../../../common/api";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
interface IDeleteUserProps {
|
||||
closeDeleteModalAndRefresh: (refresh: boolean) => void;
|
||||
deleteOpen: boolean;
|
||||
selectedUsers: string[] | null;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
}
|
||||
|
||||
const DeleteUser = ({
|
||||
closeDeleteModalAndRefresh,
|
||||
deleteOpen,
|
||||
selectedUsers,
|
||||
setErrorSnackMessage,
|
||||
}: IDeleteUserProps) => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
|
||||
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
|
||||
const onDelError = (err: ErrorResponseHandler) =>
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
const onClose = () => closeDeleteModalAndRefresh(false);
|
||||
|
||||
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
|
||||
@@ -67,11 +65,11 @@ const DeleteUser = ({
|
||||
setLoadingSA(false);
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setErrorSnackMessage(err);
|
||||
dispatch(setErrorSnackMessage(err));
|
||||
setLoadingSA(false);
|
||||
});
|
||||
}
|
||||
}, [selectedUsers, setErrorSnackMessage]);
|
||||
}, [selectedUsers, dispatch]);
|
||||
|
||||
if (!selectedUsers) {
|
||||
return null;
|
||||
@@ -97,10 +95,12 @@ const DeleteUser = ({
|
||||
const onConfirmDelete = () => {
|
||||
for (let user of selectedUsers) {
|
||||
if (user === userLoggedIn) {
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Cannot delete currently logged in user",
|
||||
detailedError: `Cannot delete currently logged in user ${userLoggedIn}`,
|
||||
});
|
||||
dispatch(
|
||||
setErrorSnackMessage({
|
||||
errorMessage: "Cannot delete currently logged in user",
|
||||
detailedError: `Cannot delete currently logged in user ${userLoggedIn}`,
|
||||
})
|
||||
);
|
||||
closeDeleteModalAndRefresh(true);
|
||||
} else {
|
||||
invokeDeleteApi("DELETE", `/api/v1/user/${encodeURLString(user)}`);
|
||||
@@ -122,9 +122,7 @@ const DeleteUser = ({
|
||||
"user" +
|
||||
(selectedUsers.length > 1 ? "s?" : "?");
|
||||
|
||||
return loadingSA ? (
|
||||
<Loader />
|
||||
) : (
|
||||
return (
|
||||
<ConfirmDialog
|
||||
title={`Delete User${selectedUsers.length > 1 ? "s" : ""}`}
|
||||
confirmText={"Delete"}
|
||||
@@ -134,45 +132,43 @@ const DeleteUser = ({
|
||||
onConfirm={onConfirmDelete}
|
||||
onClose={onClose}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
{hasSA ? (
|
||||
<Fragment>
|
||||
<WarningMessage
|
||||
label="Click on a user to view the full listing of asociated Access Keys. All Access Keys associated with a user will be deleted along with the user. Are you sure you want to continue?"
|
||||
title="Warning: One or more users selected has associated Access Keys. "
|
||||
/>
|
||||
<TableWrapper
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{ label: "Username", elementKey: "userName" },
|
||||
{
|
||||
label: "# Associated Access Keys",
|
||||
elementKey: "numSAs",
|
||||
},
|
||||
]}
|
||||
isLoading={loadingSA}
|
||||
records={userSAList}
|
||||
entityName="User Access Keys"
|
||||
idField="userName"
|
||||
customPaperHeight="250"
|
||||
/>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
{noSAtext}
|
||||
{renderUsers}
|
||||
</Fragment>
|
||||
)}
|
||||
</DialogContentText>
|
||||
loadingSA ? (
|
||||
<Loader />
|
||||
) : (
|
||||
<Fragment>
|
||||
{hasSA ? (
|
||||
<Fragment>
|
||||
<WarningMessage
|
||||
label="Click on a user to view the full listing of asociated Access Keys. All Access Keys associated with a user will be deleted along with the user. Are you sure you want to continue?"
|
||||
title="Warning: One or more users selected has associated Access Keys. "
|
||||
/>
|
||||
<DataTable
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{ label: "Username", elementKey: "userName" },
|
||||
{
|
||||
label: "# Associated Access Keys",
|
||||
elementKey: "numSAs",
|
||||
},
|
||||
]}
|
||||
isLoading={loadingSA}
|
||||
records={userSAList}
|
||||
entityName="User Access Keys"
|
||||
idField="userName"
|
||||
customPaperHeight="250"
|
||||
/>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
{noSAtext}
|
||||
{renderUsers}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setErrorSnackMessage,
|
||||
};
|
||||
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
|
||||
export default connector(DeleteUser);
|
||||
export default DeleteUser;
|
||||
|
||||
@@ -14,63 +14,24 @@
|
||||
// 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 { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import React, { useCallback, useEffect, useState, Fragment } from "react";
|
||||
import get from "lodash/get";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { Box, DataTable, Grid } from "mds";
|
||||
import { stringSort } from "../../../utils/sortFunctions";
|
||||
import { GroupsList } from "../Groups/types";
|
||||
import {
|
||||
actionsTray,
|
||||
selectorsCommon,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import api from "../../../common/api";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import api from "../../../common/api";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
|
||||
interface IGroupsProps {
|
||||
classes: any;
|
||||
selectedGroups: string[];
|
||||
setSelectedGroups: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
noFound: {
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
},
|
||||
actionsTitle: {
|
||||
fontWeight: 400,
|
||||
color: "#000",
|
||||
fontSize: 14,
|
||||
alignSelf: "center",
|
||||
|
||||
marginRight: 48,
|
||||
"@media (max-width: 900px)": {
|
||||
marginRight: 0,
|
||||
},
|
||||
},
|
||||
searchBox: {
|
||||
flex: 1,
|
||||
marginLeft: "2rem",
|
||||
},
|
||||
...tableStyles,
|
||||
...actionsTray,
|
||||
...selectorsCommon,
|
||||
});
|
||||
|
||||
const GroupsSelectors = ({
|
||||
classes,
|
||||
selectedGroups,
|
||||
setSelectedGroups,
|
||||
}: IGroupsProps) => {
|
||||
@@ -135,41 +96,41 @@ const GroupsSelectors = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12}>
|
||||
{loading && <LinearProgress />}
|
||||
{records !== null && records.length > 0 ? (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<label className={classes.actionsTitle}>Assign Groups</label>
|
||||
|
||||
<div className={classes.searchBox}>
|
||||
<SearchBox
|
||||
placeholder="Start typing to search for Groups"
|
||||
onChange={setFilter}
|
||||
value={filter}
|
||||
/>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
columns={[{ label: "Group", elementKey: "" }]}
|
||||
onSelect={selectionChanged}
|
||||
selectedItems={selGroups}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
customPaperHeight={classes.multiSelectTable}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<div className={classes.noFound}>No Groups Available</div>
|
||||
)}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
<Grid item xs={12} className={"inputItem"}>
|
||||
{loading && <LinearProgress />}
|
||||
{records !== null && records.length > 0 ? (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={"inputItem"}>
|
||||
<SearchBox
|
||||
placeholder="Start typing to search for Groups"
|
||||
onChange={setFilter}
|
||||
value={filter}
|
||||
label={"Assign Groups"}
|
||||
/>
|
||||
</Grid>
|
||||
<DataTable
|
||||
columns={[{ label: "Group" }]}
|
||||
onSelect={selectionChanged}
|
||||
selectedItems={selGroups}
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
customPaperHeight={"200px"}
|
||||
/>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
padding: "10px 0",
|
||||
}}
|
||||
>
|
||||
No Groups Available
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(GroupsSelectors);
|
||||
export default GroupsSelectors;
|
||||
|
||||
@@ -26,11 +26,13 @@ import {
|
||||
HelpBox,
|
||||
PageLayout,
|
||||
UsersIcon,
|
||||
DataTable,
|
||||
Grid,
|
||||
} from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import api from "../../../common/api";
|
||||
import { Grid, LinearProgress } from "@mui/material";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { User, UsersList } from "./types";
|
||||
import { usersSort } from "../../../utils/sortFunctions";
|
||||
import {
|
||||
@@ -40,8 +42,6 @@ import {
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import { encodeURLString } from "../../../common/utils";
|
||||
import AButton from "../Common/AButton/AButton";
|
||||
import SearchBox from "../Common/SearchBox";
|
||||
@@ -117,8 +117,8 @@ const ListUsers = ({ classes }: IUsersProps) => {
|
||||
setDeleteOpen(false);
|
||||
if (refresh) {
|
||||
setLoading(true);
|
||||
setCheckedUsers([]);
|
||||
}
|
||||
setCheckedUsers([]);
|
||||
};
|
||||
|
||||
const closeAddGroupBulk = (unCheckAll: boolean = false) => {
|
||||
@@ -218,7 +218,7 @@ const ListUsers = ({ classes }: IUsersProps) => {
|
||||
<PageHeaderWrapper label={"Users"} actions={<HelpMenu />} />
|
||||
|
||||
<PageLayout>
|
||||
<Grid container spacing={1}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<SearchBox
|
||||
placeholder={"Search Users"}
|
||||
@@ -356,14 +356,14 @@ const ListUsers = ({ classes }: IUsersProps) => {
|
||||
item
|
||||
xs={12}
|
||||
className={classes.tableBlock}
|
||||
marginBottom={"15px"}
|
||||
sx={{ marginBottom: 15 }}
|
||||
>
|
||||
<SecureComponent
|
||||
scopes={[IAM_SCOPES.ADMIN_LIST_USERS]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TableWrapper
|
||||
<DataTable
|
||||
itemActions={tableActions}
|
||||
columns={[
|
||||
{ label: "Access Key", elementKey: "accessKey" },
|
||||
@@ -428,12 +428,7 @@ const ListUsers = ({ classes }: IUsersProps) => {
|
||||
</Fragment>
|
||||
)}
|
||||
{records.length === 0 && (
|
||||
<Grid
|
||||
container
|
||||
justifyContent={"center"}
|
||||
alignContent={"center"}
|
||||
alignItems={"start"}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={8}>
|
||||
<HelpBox
|
||||
title={"Users"}
|
||||
|
||||
@@ -15,18 +15,14 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { InputBox } from "mds";
|
||||
import { setSecretKey, setShowPassword } from "./AddUsersSlice";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||
|
||||
interface IAddUserProps2 {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const PasswordSelector = ({ classes }: IAddUserProps2) => {
|
||||
const PasswordSelector = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const showPassword = useSelector(
|
||||
(state: AppState) => state.createUser.showPassword
|
||||
@@ -35,11 +31,7 @@ const PasswordSelector = ({ classes }: IAddUserProps2) => {
|
||||
(state: AppState) => state.createUser.secretKey
|
||||
);
|
||||
return (
|
||||
<InputBoxWrapper
|
||||
className={classes.spacerBottom}
|
||||
classes={{
|
||||
inputLabel: classes.sizedLabel,
|
||||
}}
|
||||
<InputBox
|
||||
id="standard-multiline-static"
|
||||
name="standard-multiline-static"
|
||||
label="Password"
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Button } from "mds";
|
||||
import { Box, Button, FormLayout, IAMPoliciesIcon } from "mds";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { useSelector } from "react-redux";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { modalBasic } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { IPolicyItem } from "../Users/types";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
@@ -33,28 +30,13 @@ import { AppState, useAppDispatch } from "../../../store";
|
||||
import { setSelectedPolicies } from "./AddUsersSlice";
|
||||
|
||||
interface ISetUserPoliciesProps {
|
||||
classes: any;
|
||||
closeModalAndRefresh: () => void;
|
||||
selectedUser: string;
|
||||
currentPolicies: IPolicyItem[];
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalBasic,
|
||||
buttonContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: ".9rem",
|
||||
"& button": {
|
||||
marginLeft: 8,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const SetUserPolicies = ({
|
||||
classes,
|
||||
closeModalAndRefresh,
|
||||
selectedUser,
|
||||
currentPolicies,
|
||||
@@ -114,19 +96,17 @@ const SetUserPolicies = ({
|
||||
}}
|
||||
modalOpen={open}
|
||||
title="Set Policies"
|
||||
titleIcon={<IAMPoliciesIcon />}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<PolicySelectors selectedPolicy={statePolicies} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<PolicySelectors selectedPolicy={statePolicies} />
|
||||
</FormLayout>
|
||||
<Box sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"reset-user-policies"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
color="primary"
|
||||
className={classes.clearButton}
|
||||
onClick={resetSelection}
|
||||
label={"Reset"}
|
||||
/>
|
||||
@@ -139,7 +119,7 @@ const SetUserPolicies = ({
|
||||
onClick={SetUserPoliciesAction}
|
||||
label={"Save"}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
{loading && (
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
@@ -149,4 +129,4 @@ const SetUserPolicies = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(SetUserPolicies);
|
||||
export default SetUserPolicies;
|
||||
|
||||
@@ -16,41 +16,25 @@
|
||||
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import {
|
||||
AddIcon,
|
||||
BackLink,
|
||||
Box,
|
||||
Button,
|
||||
DataTable,
|
||||
Grid,
|
||||
IAMPoliciesIcon,
|
||||
PageLayout,
|
||||
PasswordKeyIcon,
|
||||
ScreenTitle,
|
||||
SectionTitle,
|
||||
Switch,
|
||||
Tabs,
|
||||
TrashIcon,
|
||||
UsersIcon,
|
||||
} from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Grid } from "@mui/material";
|
||||
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { IPolicyItem } from "./types";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import api from "../../../common/api";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import ChangeUserGroups from "./ChangeUserGroups";
|
||||
import SetUserPolicies from "./SetUserPolicies";
|
||||
import UserServiceAccountsPanel from "./UserServiceAccountsPanel";
|
||||
import ChangeUserPasswordModal from "../Account/ChangeUserPasswordModal";
|
||||
import DeleteUser from "./DeleteUser";
|
||||
import ScreenTitle from "../Common/ScreenTitle/ScreenTitle";
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
import VerticalTabs from "../Common/VerticalTabs/VerticalTabs";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
|
||||
import { decodeURLString, encodeURLString } from "../../../common/utils";
|
||||
import { setHelpName, setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import {
|
||||
@@ -72,36 +56,18 @@ import { policyDetailsSort } from "../../../utils/sortFunctions";
|
||||
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
pageContainer: {
|
||||
border: "1px solid #EAEAEA",
|
||||
},
|
||||
statusLabel: {
|
||||
fontSize: ".8rem",
|
||||
marginRight: ".5rem",
|
||||
},
|
||||
statusValue: {
|
||||
fontWeight: "bold",
|
||||
fontSize: ".9rem",
|
||||
marginRight: ".5rem",
|
||||
},
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
...tableStyles,
|
||||
...containerForHeader,
|
||||
});
|
||||
|
||||
interface IUserDetailsProps {
|
||||
classes: any;
|
||||
}
|
||||
import api from "../../../common/api";
|
||||
import ChangeUserGroups from "./ChangeUserGroups";
|
||||
import SetUserPolicies from "./SetUserPolicies";
|
||||
import UserServiceAccountsPanel from "./UserServiceAccountsPanel";
|
||||
import ChangeUserPasswordModal from "../Account/ChangeUserPasswordModal";
|
||||
import DeleteUser from "./DeleteUser";
|
||||
|
||||
interface IGroupItem {
|
||||
group: string;
|
||||
}
|
||||
|
||||
const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
const UserDetails = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
@@ -118,6 +84,7 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [hasPolicy, setHasPolicy] = useState<boolean>(false);
|
||||
const [selectedTab, setSelectedTab] = useState<string>("groups");
|
||||
|
||||
const enableEnabled =
|
||||
hasPermission(CONSOLE_UI_RESOURCE, enableUserPermissions) && !enabled;
|
||||
@@ -238,17 +205,6 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeaderWrapper
|
||||
label={
|
||||
<Fragment>
|
||||
<BackLink
|
||||
label={"Users"}
|
||||
onClick={() => navigate(IAM_PAGES.USERS)}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
actions={<HelpMenu />}
|
||||
/>
|
||||
{addGroupOpen && (
|
||||
<ChangeUserGroups
|
||||
open={addGroupOpen}
|
||||
@@ -286,20 +242,41 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
closeModal={() => setChangeUserPasswordModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
<PageLayout className={classes.pageContainer}>
|
||||
<Grid container spacing={1}>
|
||||
<PageHeaderWrapper
|
||||
label={
|
||||
<Fragment>
|
||||
<BackLink
|
||||
label={"Users"}
|
||||
onClick={() => navigate(IAM_PAGES.USERS)}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
actions={<HelpMenu />}
|
||||
/>
|
||||
<PageLayout>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<ScreenTitle
|
||||
icon={
|
||||
<Fragment>
|
||||
<UsersIcon width={40} />
|
||||
</Fragment>
|
||||
}
|
||||
icon={<UsersIcon width={40} />}
|
||||
title={userName}
|
||||
subTitle={""}
|
||||
actions={
|
||||
<Fragment>
|
||||
<span className={classes.statusLabel}>User Status:</span>
|
||||
<span className={classes.statusValue}>
|
||||
<span
|
||||
style={{
|
||||
fontSize: ".8rem",
|
||||
marginRight: ".5rem",
|
||||
}}
|
||||
>
|
||||
User Status:
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
fontSize: ".9rem",
|
||||
marginRight: ".5rem",
|
||||
}}
|
||||
>
|
||||
{enabled ? "Enabled" : "Disabled"}
|
||||
</span>
|
||||
<TooltipWrapper
|
||||
@@ -328,7 +305,7 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
)
|
||||
}
|
||||
>
|
||||
<FormSwitchWrapper
|
||||
<Switch
|
||||
indicatorLabels={["Enabled", "Disabled"]}
|
||||
checked={enabled}
|
||||
value={"group_enabled"}
|
||||
@@ -378,144 +355,162 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
</TooltipWrapper>
|
||||
</Fragment>
|
||||
}
|
||||
sx={{ marginBottom: 15 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<VerticalTabs>
|
||||
{{
|
||||
tabConfig: {
|
||||
label: "Groups",
|
||||
disabled: !canAssignGroup,
|
||||
},
|
||||
content: (
|
||||
<React.Fragment>
|
||||
<div
|
||||
className={classes.actionsTray}
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_groups"))
|
||||
}
|
||||
>
|
||||
<PanelTitle>Groups</PanelTitle>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canAssignGroup
|
||||
? "Assign groups"
|
||||
: permissionTooltipHelper(
|
||||
assignGroupPermissions,
|
||||
"add users to groups"
|
||||
)
|
||||
<Tabs
|
||||
currentTabOrPath={selectedTab}
|
||||
onTabClick={setSelectedTab}
|
||||
options={[
|
||||
{
|
||||
tabConfig: {
|
||||
id: "groups",
|
||||
label: "Groups",
|
||||
disabled: !canAssignGroup,
|
||||
},
|
||||
content: (
|
||||
<React.Fragment>
|
||||
<Box
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_groups"))
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"add-groups"}
|
||||
label={"Add to Groups"}
|
||||
onClick={() => {
|
||||
setAddGroupOpen(true);
|
||||
}}
|
||||
icon={<AddIcon />}
|
||||
variant={"callAction"}
|
||||
disabled={!canAssignGroup}
|
||||
<SectionTitle
|
||||
separator
|
||||
sx={{ marginBottom: 15 }}
|
||||
actions={
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canAssignGroup
|
||||
? "Assign groups"
|
||||
: permissionTooltipHelper(
|
||||
assignGroupPermissions,
|
||||
"add users to groups"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"add-groups"}
|
||||
label={"Add to Groups"}
|
||||
onClick={() => {
|
||||
setAddGroupOpen(true);
|
||||
}}
|
||||
icon={<AddIcon />}
|
||||
variant={"callAction"}
|
||||
disabled={!canAssignGroup}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
}
|
||||
>
|
||||
Groups
|
||||
</SectionTitle>
|
||||
</Box>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_groups"))
|
||||
}
|
||||
>
|
||||
<DataTable
|
||||
itemActions={groupTableActions}
|
||||
columns={[{ label: "Name", elementKey: "group" }]}
|
||||
isLoading={loading}
|
||||
records={currentGroups}
|
||||
entityName="Groups"
|
||||
idField="group"
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
className={classes.tableBlock}
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_groups"))
|
||||
}
|
||||
>
|
||||
<TableWrapper
|
||||
itemActions={groupTableActions}
|
||||
columns={[{ label: "Name", elementKey: "group" }]}
|
||||
isLoading={loading}
|
||||
records={currentGroups}
|
||||
entityName="Groups"
|
||||
idField="group"
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
),
|
||||
}}
|
||||
{{
|
||||
tabConfig: {
|
||||
label: "Service Accounts",
|
||||
disabled: !hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
editServiceAccountPermissions
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
),
|
||||
},
|
||||
content: (
|
||||
<UserServiceAccountsPanel
|
||||
user={userName}
|
||||
hasPolicy={hasPolicy}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
{{
|
||||
tabConfig: {
|
||||
label: "Policies",
|
||||
disabled: !canAssignPolicy,
|
||||
{
|
||||
tabConfig: {
|
||||
id: "service_accounts",
|
||||
label: "Service Accounts",
|
||||
disabled: !hasPermission(
|
||||
CONSOLE_UI_RESOURCE,
|
||||
editServiceAccountPermissions
|
||||
),
|
||||
},
|
||||
content: (
|
||||
<UserServiceAccountsPanel
|
||||
user={userName}
|
||||
hasPolicy={hasPolicy}
|
||||
/>
|
||||
),
|
||||
},
|
||||
content: (
|
||||
<Fragment>
|
||||
<div
|
||||
className={classes.actionsTray}
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_policies"))
|
||||
}
|
||||
>
|
||||
<PanelTitle>Policies</PanelTitle>
|
||||
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canAssignPolicy
|
||||
? "Assign Policies"
|
||||
: permissionTooltipHelper(
|
||||
assignIAMPolicyPermissions,
|
||||
"assign policies"
|
||||
)
|
||||
{
|
||||
tabConfig: {
|
||||
id: "policies",
|
||||
label: "Policies",
|
||||
disabled: !canAssignPolicy,
|
||||
},
|
||||
content: (
|
||||
<Fragment>
|
||||
<Box
|
||||
onMouseMove={() =>
|
||||
dispatch(setHelpName("user_details_policies"))
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"assign-policies"}
|
||||
label={"Assign Policies"}
|
||||
onClick={() => {
|
||||
setPolicyOpen(true);
|
||||
}}
|
||||
icon={<IAMPoliciesIcon />}
|
||||
variant={"callAction"}
|
||||
disabled={!canAssignPolicy}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
<div className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
itemActions={[
|
||||
{
|
||||
type: "view",
|
||||
onClick: (policy: IPolicyItem) => {
|
||||
navigate(
|
||||
`${IAM_PAGES.POLICIES}/${encodeURLString(
|
||||
policy.policy
|
||||
)}`
|
||||
);
|
||||
<SectionTitle
|
||||
separator
|
||||
sx={{ marginBottom: 15 }}
|
||||
actions={
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
canAssignPolicy
|
||||
? "Assign Policies"
|
||||
: permissionTooltipHelper(
|
||||
assignIAMPolicyPermissions,
|
||||
"assign policies"
|
||||
)
|
||||
}
|
||||
>
|
||||
<Button
|
||||
id={"assign-policies"}
|
||||
label={"Assign Policies"}
|
||||
onClick={() => {
|
||||
setPolicyOpen(true);
|
||||
}}
|
||||
icon={<IAMPoliciesIcon />}
|
||||
variant={"callAction"}
|
||||
disabled={!canAssignPolicy}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
}
|
||||
>
|
||||
Policies
|
||||
</SectionTitle>
|
||||
</Box>
|
||||
<Box>
|
||||
<DataTable
|
||||
itemActions={[
|
||||
{
|
||||
type: "view",
|
||||
onClick: (policy: IPolicyItem) => {
|
||||
navigate(
|
||||
`${IAM_PAGES.POLICIES}/${encodeURLString(
|
||||
policy.policy
|
||||
)}`
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
columns={[{ label: "Name", elementKey: "policy" }]}
|
||||
isLoading={loading}
|
||||
records={currentPolicies}
|
||||
entityName="Policies"
|
||||
idField="policy"
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
),
|
||||
}}
|
||||
</VerticalTabs>
|
||||
]}
|
||||
columns={[{ label: "Name", elementKey: "policy" }]}
|
||||
isLoading={loading}
|
||||
records={currentPolicies}
|
||||
entityName="Policies"
|
||||
idField="policy"
|
||||
/>
|
||||
</Box>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</PageLayout>
|
||||
@@ -523,4 +518,4 @@ const UserDetails = ({ classes }: IUserDetailsProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(UserDetails);
|
||||
export default UserDetails;
|
||||
|
||||
@@ -14,36 +14,26 @@
|
||||
// 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, { Fragment } from "react";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import React from "react";
|
||||
import { setUserName } from "./AddUsersSlice";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import { InputBox } from "mds";
|
||||
|
||||
interface IAddUserProps2 {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const UserSelector = ({ classes }: IAddUserProps2) => {
|
||||
const UserSelector = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const userName = useSelector((state: AppState) => state.createUser.userName);
|
||||
return (
|
||||
<Fragment>
|
||||
<InputBoxWrapper
|
||||
className={classes.spacerBottom}
|
||||
classes={{
|
||||
inputLabel: classes.sizedLabel,
|
||||
}}
|
||||
id="accesskey-input"
|
||||
name="accesskey-input"
|
||||
label="User Name"
|
||||
value={userName}
|
||||
autoFocus={true}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(setUserName(e.target.value));
|
||||
}}
|
||||
/>
|
||||
</Fragment>
|
||||
<InputBox
|
||||
id="accesskey-input"
|
||||
name="accesskey-input"
|
||||
label="User Name"
|
||||
value={userName}
|
||||
autoFocus={true}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(setUserName(e.target.value));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default UserSelector;
|
||||
|
||||
@@ -14,27 +14,15 @@
|
||||
// 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 } from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Box } from "@mui/material";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { AddIcon, Button, DeleteIcon } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
actionsTray,
|
||||
searchField,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { AddIcon, Box, Button, DataTable, DeleteIcon, SectionTitle } from "mds";
|
||||
import api from "../../../common/api";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import { NewServiceAccount } from "../Common/CredentialsPrompt/types";
|
||||
import { stringSort } from "../../../utils/sortFunctions";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import AddUserServiceAccount from "./AddUserServiceAccount";
|
||||
import DeleteServiceAccount from "../Account/DeleteServiceAccount";
|
||||
import CredentialsPrompt from "../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
|
||||
import DeleteMultipleServiceAccounts from "./DeleteMultipleServiceAccounts";
|
||||
import { selectSAs } from "../Configurations/utils";
|
||||
@@ -54,23 +42,11 @@ import { useAppDispatch } from "../../../store";
|
||||
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
|
||||
|
||||
interface IUserServiceAccountsProps {
|
||||
classes: any;
|
||||
user: string;
|
||||
hasPolicy: boolean;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...searchField,
|
||||
...actionsTray,
|
||||
actionsTray: {
|
||||
...actionsTray.actionsTray,
|
||||
},
|
||||
...tableStyles,
|
||||
});
|
||||
|
||||
const UserServiceAccountsPanel = ({
|
||||
classes,
|
||||
user,
|
||||
hasPolicy,
|
||||
}: IUserServiceAccountsProps) => {
|
||||
@@ -79,7 +55,6 @@ const UserServiceAccountsPanel = ({
|
||||
|
||||
const [records, setRecords] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [addScreenOpen, setAddScreenOpen] = useState<boolean>(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [selectedServiceAccount, setSelectedServiceAccount] = useState<
|
||||
string | null
|
||||
@@ -115,23 +90,6 @@ const UserServiceAccountsPanel = ({
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
const closeAddModalAndRefresh = (res: NewServiceAccount | null) => {
|
||||
setAddScreenOpen(false);
|
||||
fetchRecords();
|
||||
|
||||
if (res !== null) {
|
||||
const nsa: NewServiceAccount = {
|
||||
console: {
|
||||
accessKey: `${res.accessKey}`,
|
||||
secretKey: `${res.secretKey}`,
|
||||
url: `${res.url}`,
|
||||
},
|
||||
};
|
||||
setNewServiceAccount(nsa);
|
||||
setShowNewCredentials(true);
|
||||
}
|
||||
};
|
||||
|
||||
const closeDeleteModalAndRefresh = (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
@@ -188,16 +146,7 @@ const UserServiceAccountsPanel = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
return (
|
||||
<React.Fragment>
|
||||
{addScreenOpen && (
|
||||
<AddUserServiceAccount
|
||||
open={addScreenOpen}
|
||||
closeModalAndRefresh={(res: NewServiceAccount | null) => {
|
||||
closeAddModalAndRefresh(res);
|
||||
}}
|
||||
user={user}
|
||||
/>
|
||||
)}
|
||||
<Fragment>
|
||||
{deleteOpen && (
|
||||
<DeleteServiceAccount
|
||||
deleteOpen={deleteOpen}
|
||||
@@ -231,64 +180,68 @@ const UserServiceAccountsPanel = ({
|
||||
closeModalAndRefresh={closePolicyModal}
|
||||
/>
|
||||
)}
|
||||
<div className={classes.actionsTray}>
|
||||
<PanelTitle>Access Keys</PanelTitle>
|
||||
<Box sx={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<TooltipWrapper tooltip={"Delete Selected"}>
|
||||
<Button
|
||||
id={"delete-selected"}
|
||||
onClick={() => {
|
||||
setDeleteMultipleOpen(true);
|
||||
}}
|
||||
label={"Delete Selected"}
|
||||
icon={<DeleteIcon />}
|
||||
disabled={selectedSAs.length === 0}
|
||||
variant={"secondary"}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
<SecureComponent
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_UPDATE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_REMOVE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_LIST_SERVICEACCOUNTS,
|
||||
]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={"Create Access Key"}>
|
||||
|
||||
<SectionTitle
|
||||
separator
|
||||
sx={{ marginBottom: 15 }}
|
||||
actions={
|
||||
<Box sx={{ display: "flex", justifyContent: "flex-end", gap: 10 }}>
|
||||
<TooltipWrapper tooltip={"Delete Selected"}>
|
||||
<Button
|
||||
id={"create-service-account"}
|
||||
label={"Create Access Key"}
|
||||
variant="callAction"
|
||||
icon={<AddIcon />}
|
||||
id={"delete-selected"}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`/identity/users/new-user-sa/${encodeURLString(user)}`
|
||||
);
|
||||
setDeleteMultipleOpen(true);
|
||||
}}
|
||||
disabled={!hasPolicy}
|
||||
label={"Delete Selected"}
|
||||
icon={<DeleteIcon />}
|
||||
disabled={selectedSAs.length === 0}
|
||||
variant={"secondary"}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
</Box>
|
||||
</div>
|
||||
<div className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
isLoading={loading}
|
||||
records={records}
|
||||
entityName={"Access Keys"}
|
||||
idField={""}
|
||||
columns={[{ label: "Access Key", elementKey: "" }]}
|
||||
itemActions={tableActions}
|
||||
selectedItems={selectedSAs}
|
||||
onSelect={(e) => selectSAs(e, setSelectedSAs, selectedSAs)}
|
||||
onSelectAll={selectAllItems}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
<SecureComponent
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_CREATE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_UPDATE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_REMOVE_SERVICEACCOUNT,
|
||||
IAM_SCOPES.ADMIN_LIST_SERVICEACCOUNTS,
|
||||
]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<TooltipWrapper tooltip={"Create Access Key"}>
|
||||
<Button
|
||||
id={"create-service-account"}
|
||||
label={"Create Access Key"}
|
||||
variant="callAction"
|
||||
icon={<AddIcon />}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`/identity/users/new-user-sa/${encodeURLString(user)}`
|
||||
);
|
||||
}}
|
||||
disabled={!hasPolicy}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</SecureComponent>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
Access Keys
|
||||
</SectionTitle>
|
||||
|
||||
<DataTable
|
||||
isLoading={loading}
|
||||
records={records}
|
||||
entityName={"Access Keys"}
|
||||
columns={[{ label: "Access Key" }]}
|
||||
itemActions={tableActions}
|
||||
selectedItems={selectedSAs}
|
||||
onSelect={(e) => selectSAs(e, setSelectedSAs, selectedSAs)}
|
||||
onSelectAll={selectAllItems}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(UserServiceAccountsPanel);
|
||||
export default UserServiceAccountsPanel;
|
||||
|
||||
@@ -54,8 +54,9 @@ export const createUserAsync = createAsyncThunk(
|
||||
groups: selectedGroups,
|
||||
policies: selectedPolicies,
|
||||
})
|
||||
.then((res) => {
|
||||
.then(() => {
|
||||
dispatch(setAddLoading(false));
|
||||
dispatch(resetFormAsync());
|
||||
})
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
dispatch(setAddLoading(false));
|
||||
|
||||
@@ -32,7 +32,7 @@ const userDeleteIconButton = userListItem
|
||||
.child("checkbox")
|
||||
.withAttribute("aria-label", "secondary checkbox");
|
||||
|
||||
const userCheckbox = Selector(".TableCheckbox");
|
||||
const userCheckbox = Selector(".TableCheckbox span.checkbox");
|
||||
|
||||
fixture("For user with Users permissions")
|
||||
.page("http://localhost:9090")
|
||||
@@ -100,8 +100,10 @@ test("IAM Policy can be set on User", async (t) => {
|
||||
|
||||
test("Created User can be viewed and deleted", async (t) => {
|
||||
const userListItemExists = userListItem.exists;
|
||||
const deleteSelectedButton =
|
||||
Selector("button:enabled").withExactText("Delete Selected");
|
||||
const deleteSelectedButton = Selector("button").withAttribute(
|
||||
"id",
|
||||
"delete-selected-users"
|
||||
);
|
||||
await t
|
||||
.navigateTo(usersPageUrl)
|
||||
.typeText(elements.searchResourceInput, constants.TEST_USER_NAME)
|
||||
|
||||
@@ -44,8 +44,10 @@ export const startDiagnosticButton =
|
||||
export const startNewDiagnosticButton = Selector("#start-new-diagnostic");
|
||||
export const downloadButton = Selector("button:enabled").withText("Download");
|
||||
export const startButton = Selector("button:enabled").withText("Start");
|
||||
export const assignPoliciesButton =
|
||||
Selector("button:enabled").withText("Assign Policies");
|
||||
export const assignPoliciesButton = Selector("button").withAttribute(
|
||||
"id",
|
||||
"assign-policies"
|
||||
);
|
||||
|
||||
//----------------------------------------------------
|
||||
// Switches
|
||||
@@ -178,7 +180,10 @@ export const nodeSelector = Selector('[data-test-id="node-selector"]');
|
||||
//----------------------------------------------------
|
||||
// User Details
|
||||
//----------------------------------------------------
|
||||
export const userPolicies = Selector(".MuiTab-root").withText("Policies");
|
||||
export const userPolicies = Selector(".optionsList button").withAttribute(
|
||||
"id",
|
||||
"policies"
|
||||
);
|
||||
//----------------------------------------------------
|
||||
// Rewind Options
|
||||
//----------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user