Migrated Access Keys page components to mds (#2834)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -18,24 +18,21 @@ import React, { Fragment, useEffect, useState } from "react";
|
||||
import {
|
||||
AccountIcon,
|
||||
AddIcon,
|
||||
Box,
|
||||
Button,
|
||||
DataTable,
|
||||
DeleteIcon,
|
||||
Grid,
|
||||
HelpBox,
|
||||
PageLayout,
|
||||
PasswordKeyIcon,
|
||||
} from "mds";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import api from "../../../common/api";
|
||||
import { Box } from "@mui/material";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import { stringSort } from "../../../utils/sortFunctions";
|
||||
import {
|
||||
actionsTray,
|
||||
searchField,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
|
||||
@@ -54,7 +51,6 @@ import { selectSAs } from "../Configurations/utils";
|
||||
import DeleteMultipleServiceAccounts from "../Users/DeleteMultipleServiceAccounts";
|
||||
import ServiceAccountPolicy from "./ServiceAccountPolicy";
|
||||
import { setErrorSnackMessage, setSnackBarMessage } from "../../../systemSlice";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { selFeatures } from "../consoleSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper";
|
||||
@@ -64,24 +60,10 @@ const DeleteServiceAccount = withSuspense(
|
||||
React.lazy(() => import("./DeleteServiceAccount"))
|
||||
);
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
searchField: {
|
||||
...searchField.searchField,
|
||||
marginRight: "auto",
|
||||
maxWidth: 380,
|
||||
},
|
||||
...tableStyles,
|
||||
})
|
||||
);
|
||||
|
||||
const Account = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const classes = useStyles();
|
||||
const features = useSelector(selFeatures);
|
||||
|
||||
const [records, setRecords] = useState<string[]>([]);
|
||||
@@ -199,27 +181,29 @@ const Account = () => {
|
||||
closeModalAndRefresh={closePolicyModal}
|
||||
/>
|
||||
)}
|
||||
<ChangePasswordModal
|
||||
open={changePasswordModalOpen}
|
||||
closeModal={() => setChangePasswordModalOpen(false)}
|
||||
/>
|
||||
{changePasswordModalOpen && (
|
||||
<ChangePasswordModal
|
||||
open={changePasswordModalOpen}
|
||||
closeModal={() => setChangePasswordModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
<PageHeaderWrapper label="Access Keys" />
|
||||
<PageLayout>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item={true} xs={12} className={classes.actionsTray}>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sx={{ ...actionsTray.actionsTray }}>
|
||||
<SearchBox
|
||||
placeholder={"Search Access Keys"}
|
||||
onChange={setFilter}
|
||||
overrideClass={classes.searchField}
|
||||
sx={{ marginRight: "auto", maxWidth: 380 }}
|
||||
value={filter}
|
||||
/>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexWrap: "nowrap",
|
||||
gap: 5,
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
<TooltipWrapper tooltip={"Delete Selected"}>
|
||||
<Button
|
||||
id={"delete-selected-accounts"}
|
||||
@@ -266,20 +250,19 @@ const Account = () => {
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
<Grid item xs={12} sx={{ ...tableStyles.tableBlock }}>
|
||||
<DataTable
|
||||
isLoading={loading}
|
||||
records={filteredRecords}
|
||||
entityName={"Access Keys"}
|
||||
idField={""}
|
||||
columns={[{ label: "Access Key", elementKey: "" }]}
|
||||
columns={[{ label: "Access Key" }]}
|
||||
itemActions={tableActions}
|
||||
selectedItems={selectedSAs}
|
||||
onSelect={(e) => selectSAs(e, setSelectedSAs, selectedSAs)}
|
||||
onSelectAll={selectAllItems}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} marginTop={"15px"}>
|
||||
<Grid item xs={12} sx={{ marginTop: 15 }}>
|
||||
<HelpBox
|
||||
title={"Learn more about ACCESS KEYS"}
|
||||
iconComponent={<AccountIcon />}
|
||||
@@ -295,11 +278,8 @@ const Account = () => {
|
||||
<br />
|
||||
<br />
|
||||
You can learn more at our{" "}
|
||||
{
|
||||
// TODO: Change this link once it is called access keys
|
||||
}
|
||||
<a
|
||||
href="https://min.io/docs/minio/linux/administration/identity-access-management/minio-user-management.html?ref=con#service-accounts"
|
||||
href="https://min.io/docs/minio/linux/administration/identity-access-management/minio-user-management.html?ref=con#id3"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
|
||||
@@ -15,38 +15,30 @@
|
||||
// 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 } from "react-router-dom";
|
||||
import {
|
||||
BackLink,
|
||||
Button,
|
||||
IAMPoliciesIcon,
|
||||
PageLayout,
|
||||
PasswordKeyIcon,
|
||||
ServiceAccountCredentialsIcon,
|
||||
Grid,
|
||||
Box,
|
||||
FormLayout,
|
||||
InputBox,
|
||||
Switch,
|
||||
ServiceAccountIcon,
|
||||
} 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 { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import AddServiceAccountHelpBox from "./AddServiceAccountHelpBox";
|
||||
|
||||
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 PanelTitle from "../Common/PanelTitle/PanelTitle";
|
||||
|
||||
import { setErrorSnackMessage } from "../../../systemSlice";
|
||||
@@ -54,17 +46,7 @@ import { useAppDispatch } from "../../../store";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import { getRandomString } from "../../../common/utils";
|
||||
|
||||
interface IAddServiceAccountProps {
|
||||
classes: any;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...formFieldStyles,
|
||||
...modalStyleUtils,
|
||||
});
|
||||
|
||||
const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
const AddServiceAccount = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -75,7 +57,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>("");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -120,7 +101,6 @@ const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
setNewServiceAccount(null);
|
||||
setAccessKey("");
|
||||
setSecretKey("");
|
||||
setShowPassword(false);
|
||||
};
|
||||
|
||||
const closeCredentialsModal = () => {
|
||||
@@ -150,161 +130,96 @@ const AddServiceAccount = ({ classes }: IAddServiceAccountProps) => {
|
||||
}
|
||||
/>
|
||||
<PageLayout>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
padding: "25px",
|
||||
gap: "25px",
|
||||
gridTemplateColumns: {
|
||||
md: "2fr 1.2fr",
|
||||
xs: "1fr",
|
||||
},
|
||||
border: "1px solid #eaeaea",
|
||||
}}
|
||||
<FormLayout
|
||||
helpBox={<AddServiceAccountHelpBox />}
|
||||
icon={<ServiceAccountCredentialsIcon />}
|
||||
title={"Create Access Key"}
|
||||
>
|
||||
<Box>
|
||||
<SectionTitle icon={<ServiceAccountCredentialsIcon />}>
|
||||
Create Access Key
|
||||
</SectionTitle>
|
||||
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addServiceAccount(e);
|
||||
<form
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
addServiceAccount(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}
|
||||
>
|
||||
<div>
|
||||
<PanelTitle>
|
||||
Current User Policy - edit the JSON to remove
|
||||
permissions for this Access Key
|
||||
</PanelTitle>
|
||||
</div>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<CodeMirrorWrapper
|
||||
value={policyJSON}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setPolicyJSON(value);
|
||||
}}
|
||||
editorHeight={"350px"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||
<Button
|
||||
id={"clear"}
|
||||
type="button"
|
||||
variant="regular"
|
||||
onClick={resetForm}
|
||||
label={"Clear"}
|
||||
/>
|
||||
|
||||
<Button
|
||||
id={"create-sa"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
color="primary"
|
||||
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}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
setPolicyJSON(value);
|
||||
}}
|
||||
editorHeight={"350px"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Box>
|
||||
<AddServiceAccountHelpBox />
|
||||
</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,53 +15,27 @@
|
||||
// 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 { Button, ChangePasswordIcon, InputBox, Grid, FormLayout } from "mds";
|
||||
import ModalWrapper from "../Common/ModalWrapper/ModalWrapper";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import {
|
||||
containerForHeader,
|
||||
formFieldStyles,
|
||||
modalStyleUtils,
|
||||
spacingUtils,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ChangePasswordRequest } from "../Buckets/types";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import api from "../../../common/api";
|
||||
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
||||
import { setModalErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
...modalStyleUtils,
|
||||
...formFieldStyles,
|
||||
...spacingUtils,
|
||||
...containerForHeader,
|
||||
});
|
||||
|
||||
interface IChangePasswordProps {
|
||||
classes: any;
|
||||
open: boolean;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const ChangePassword = ({
|
||||
classes,
|
||||
open,
|
||||
closeModal,
|
||||
}: IChangePasswordProps) => {
|
||||
const ChangePassword = ({ open, closeModal }: IChangePasswordProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const [currentPassword, setCurrentPassword] = useState<string>("");
|
||||
const [newPassword, setNewPassword] = useState<string>("");
|
||||
const [reNewPassword, setReNewPassword] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||
|
||||
const userLoggedIn = localStorage.getItem("userLoggedIn") || "";
|
||||
|
||||
@@ -140,57 +114,41 @@ const ChangePassword = ({
|
||||
}}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.modalFormScrollable}>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<Grid item xs={12} sx={{ ...modalStyleUtils.modalFormScrollable }}>
|
||||
<FormLayout withBorders={false} containerPadding={false}>
|
||||
<InputBox
|
||||
id="current-password"
|
||||
name="current-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCurrentPassword(event.target.value);
|
||||
}}
|
||||
label="Current Password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
type={"password"}
|
||||
value={currentPassword}
|
||||
overlayAction={() => setShowPassword(!showPassword)}
|
||||
overlayIcon={
|
||||
showPassword ? <VisibilityOffIcon /> : <RemoveRedEyeIcon />
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="new-password"
|
||||
name="new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setNewPassword(event.target.value);
|
||||
}}
|
||||
label="New Password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
type={"password"}
|
||||
value={newPassword}
|
||||
overlayAction={() => setShowPassword(!showPassword)}
|
||||
overlayIcon={
|
||||
showPassword ? <VisibilityOffIcon /> : <RemoveRedEyeIcon />
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
<InputBox
|
||||
id="re-new-password"
|
||||
name="re-new-password"
|
||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setReNewPassword(event.target.value);
|
||||
}}
|
||||
label="Type New Password Again"
|
||||
type={showPassword ? "text" : "password"}
|
||||
type={"password"}
|
||||
value={reNewPassword}
|
||||
overlayAction={() => setShowPassword(!showPassword)}
|
||||
overlayIcon={
|
||||
showPassword ? <VisibilityOffIcon /> : <RemoveRedEyeIcon />
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</FormLayout>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.modalButtonBar}>
|
||||
<Grid item xs={12} sx={{ ...modalStyleUtils.modalButtonBar }}>
|
||||
<Button
|
||||
id={"save-password-modal"}
|
||||
type="submit"
|
||||
@@ -218,4 +176,4 @@ const ChangePassword = ({
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default withStyles(styles)(ChangePassword);
|
||||
export default ChangePassword;
|
||||
|
||||
@@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { DialogContentText } from "@mui/material";
|
||||
|
||||
import React, { Fragment } from "react";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import useApi from "../Common/Hooks/useApi";
|
||||
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
|
||||
@@ -29,24 +23,13 @@ import { encodeURLString } from "../../../common/utils";
|
||||
import { setErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
wrapText: {
|
||||
maxWidth: "200px",
|
||||
whiteSpace: "normal",
|
||||
wordWrap: "break-word",
|
||||
},
|
||||
});
|
||||
|
||||
interface IDeleteServiceAccountProps {
|
||||
classes: any;
|
||||
closeDeleteModalAndRefresh: (refresh: boolean) => void;
|
||||
deleteOpen: boolean;
|
||||
selectedServiceAccount: string | null;
|
||||
}
|
||||
|
||||
const DeleteServiceAccount = ({
|
||||
classes,
|
||||
closeDeleteModalAndRefresh,
|
||||
deleteOpen,
|
||||
selectedServiceAccount,
|
||||
@@ -80,13 +63,22 @@ const DeleteServiceAccount = ({
|
||||
onConfirm={onConfirmDelete}
|
||||
onClose={onClose}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
<Fragment>
|
||||
Are you sure you want to delete Access Key{" "}
|
||||
<b className={classes.wrapText}>{selectedServiceAccount}</b>?
|
||||
</DialogContentText>
|
||||
<b
|
||||
style={{
|
||||
maxWidth: "200px",
|
||||
whiteSpace: "normal",
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
{selectedServiceAccount}
|
||||
</b>
|
||||
?
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(DeleteServiceAccount);
|
||||
export default DeleteServiceAccount;
|
||||
|
||||
@@ -15,87 +15,46 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import { InputAdornment, OutlinedInput } from "@mui/material";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Button, CopyIcon } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import { Button, CopyIcon, InputLabel, ReadBox, Box } from "mds";
|
||||
import CopyToClipboard from "react-copy-to-clipboard";
|
||||
import { fieldBasic } from "../FormComponents/common/styleLibrary";
|
||||
import TooltipWrapper from "../TooltipWrapper/TooltipWrapper";
|
||||
import { setModalSnackMessage } from "../../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../../store";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
container: {
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
padding: "20px 0 8px 0",
|
||||
},
|
||||
inputWithCopy: {
|
||||
"& .MuiInputBase-root ": {
|
||||
width: "100%",
|
||||
background: "#FBFAFA",
|
||||
"& .MuiInputBase-input": {
|
||||
height: ".8rem",
|
||||
},
|
||||
"& .MuiInputAdornment-positionEnd": {
|
||||
marginRight: ".5rem",
|
||||
"& .MuiButtonBase-root": {
|
||||
height: "2rem",
|
||||
},
|
||||
},
|
||||
},
|
||||
"& .MuiButtonBase-root .min-icon": {
|
||||
width: ".8rem",
|
||||
height: ".8rem",
|
||||
},
|
||||
},
|
||||
inputLabel: {
|
||||
...fieldBasic.inputLabel,
|
||||
fontSize: ".8rem",
|
||||
},
|
||||
});
|
||||
interface ICredentialsItem {
|
||||
label?: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
const CredentialItem = ({ label = "", value = "" }: ICredentialsItem) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const CredentialItem = ({
|
||||
label = "",
|
||||
value = "",
|
||||
classes = {},
|
||||
}: {
|
||||
label: string;
|
||||
value: string;
|
||||
classes: any;
|
||||
}) => {
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div className={classes.inputLabel}>{label}:</div>
|
||||
<div className={classes.inputWithCopy}>
|
||||
<OutlinedInput
|
||||
value={value}
|
||||
readOnly
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<TooltipWrapper tooltip={"Copy"}>
|
||||
<CopyToClipboard text={value}>
|
||||
<Button
|
||||
id={"copy-clipboard"}
|
||||
aria-label="copy"
|
||||
onClick={() => {}}
|
||||
onMouseDown={() => {}}
|
||||
style={{
|
||||
width: "28px",
|
||||
height: "28px",
|
||||
padding: "0px",
|
||||
}}
|
||||
icon={<CopyIcon />}
|
||||
/>
|
||||
</CopyToClipboard>
|
||||
</TooltipWrapper>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Box sx={{ marginTop: 12 }}>
|
||||
<InputLabel>{label}</InputLabel>
|
||||
<ReadBox
|
||||
actionButton={
|
||||
<CopyToClipboard text={value}>
|
||||
<Button
|
||||
id={"copy-path"}
|
||||
variant="regular"
|
||||
onClick={() => {
|
||||
dispatch(setModalSnackMessage(`${label} copied to clipboard`));
|
||||
}}
|
||||
style={{
|
||||
marginRight: "5px",
|
||||
width: "28px",
|
||||
height: "28px",
|
||||
padding: "0px",
|
||||
}}
|
||||
icon={<CopyIcon />}
|
||||
/>
|
||||
</CopyToClipboard>
|
||||
}
|
||||
>
|
||||
{value}
|
||||
</ReadBox>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(CredentialItem);
|
||||
export default CredentialItem;
|
||||
|
||||
@@ -14,62 +14,37 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import get from "lodash/get";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
DownloadIcon,
|
||||
ServiceAccountCredentialsIcon,
|
||||
WarnIcon,
|
||||
Grid,
|
||||
} from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { NewServiceAccount } from "./types";
|
||||
import ModalWrapper from "../ModalWrapper/ModalWrapper";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import CredentialItem from "./CredentialItem";
|
||||
import TooltipWrapper from "../TooltipWrapper/TooltipWrapper";
|
||||
import { modalStyleUtils } from "../FormComponents/common/styleLibrary";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
warningBlock: {
|
||||
color: "red",
|
||||
fontSize: ".85rem",
|
||||
margin: ".5rem 0 .5rem 0",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
"& svg ": {
|
||||
marginRight: ".3rem",
|
||||
height: 16,
|
||||
width: 16,
|
||||
},
|
||||
},
|
||||
credentialTitle: {
|
||||
padding: ".8rem 0 0 0",
|
||||
fontWeight: 600,
|
||||
fontSize: ".9rem",
|
||||
},
|
||||
buttonContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
marginTop: "1rem",
|
||||
},
|
||||
credentialsPanel: {
|
||||
overflowY: "auto",
|
||||
maxHeight: 350,
|
||||
},
|
||||
promptTitle: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
buttonSpacer: {
|
||||
marginRight: ".9rem",
|
||||
},
|
||||
});
|
||||
const WarningBlock = styled.div(({ theme }) => ({
|
||||
color: "red", // TODO: Change this to themed color variant in mds
|
||||
fontSize: ".85rem",
|
||||
margin: ".5rem 0 .5rem 0",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
"& svg ": {
|
||||
marginRight: ".3rem",
|
||||
height: 16,
|
||||
width: 16,
|
||||
},
|
||||
}));
|
||||
|
||||
interface ICredentialsPromptProps {
|
||||
classes: any;
|
||||
newServiceAccount: NewServiceAccount | null;
|
||||
open: boolean;
|
||||
entity: string;
|
||||
@@ -89,7 +64,6 @@ const download = (filename: string, text: string) => {
|
||||
};
|
||||
|
||||
const CredentialsPrompt = ({
|
||||
classes,
|
||||
newServiceAccount,
|
||||
open,
|
||||
closeModal,
|
||||
@@ -172,26 +146,35 @@ const CredentialsPrompt = ({
|
||||
onClose={() => {
|
||||
closeModal();
|
||||
}}
|
||||
title={
|
||||
<div className={classes.promptTitle}>
|
||||
<div>New {entity} Created</div>
|
||||
</div>
|
||||
}
|
||||
title={`New ${entity} Created`}
|
||||
titleIcon={<ServiceAccountCredentialsIcon />}
|
||||
>
|
||||
<Grid container>
|
||||
<Grid item xs={12} className={classes.formScrollable}>
|
||||
<Grid item xs={12}>
|
||||
A new {entity} has been created with the following details:
|
||||
{!idp && consoleCreds && (
|
||||
<React.Fragment>
|
||||
<Grid item xs={12} className={classes.credentialsPanel}>
|
||||
<div className={classes.credentialTitle}>
|
||||
<Fragment>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
overflowY: "auto",
|
||||
maxHeight: 350,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
padding: ".8rem 0 0 0",
|
||||
fontWeight: 600,
|
||||
fontSize: ".9rem",
|
||||
}}
|
||||
>
|
||||
Console Credentials
|
||||
</div>
|
||||
</Box>
|
||||
{Array.isArray(consoleCreds) &&
|
||||
consoleCreds.map((credentialsPair, index) => {
|
||||
return (
|
||||
<>
|
||||
<Fragment>
|
||||
<CredentialItem
|
||||
label="Access Key"
|
||||
value={credentialsPair.accessKey}
|
||||
@@ -200,11 +183,11 @@ const CredentialsPrompt = ({
|
||||
label="Secret Key"
|
||||
value={credentialsPair.secretKey}
|
||||
/>
|
||||
</>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
{!Array.isArray(consoleCreds) && (
|
||||
<>
|
||||
<Fragment>
|
||||
<CredentialItem
|
||||
label="Access Key"
|
||||
value={consoleCreds.accessKey}
|
||||
@@ -213,10 +196,10 @@ const CredentialsPrompt = ({
|
||||
label="Secret Key"
|
||||
value={consoleCreds.secretKey}
|
||||
/>
|
||||
</>
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
)}
|
||||
{(consoleCreds === null || consoleCreds === undefined) && (
|
||||
<>
|
||||
@@ -231,22 +214,22 @@ const CredentialsPrompt = ({
|
||||
</>
|
||||
)}
|
||||
{idp ? (
|
||||
<div className={classes.warningBlock}>
|
||||
<WarningBlock>
|
||||
Please Login via the configured external identity provider.
|
||||
</div>
|
||||
</WarningBlock>
|
||||
) : (
|
||||
<div className={classes.warningBlock}>
|
||||
<WarningBlock>
|
||||
<WarnIcon />
|
||||
<span>
|
||||
Write these down, as this is the only time the secret will be
|
||||
displayed.
|
||||
</span>
|
||||
</div>
|
||||
</WarningBlock>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonContainer}>
|
||||
<Grid item xs={12} sx={{ ...modalStyleUtils.modalButtonBar }}>
|
||||
{!idp && (
|
||||
<>
|
||||
<Fragment>
|
||||
<TooltipWrapper
|
||||
tooltip={
|
||||
"Download credentials in a JSON file formatted for import using mc alias import. This will only include the default login credentials."
|
||||
@@ -255,7 +238,6 @@ const CredentialsPrompt = ({
|
||||
<Button
|
||||
id={"download-button"}
|
||||
label={"Download for import"}
|
||||
className={classes.buttonSpacer}
|
||||
onClick={downloadImport}
|
||||
icon={<DownloadIcon />}
|
||||
variant="callAction"
|
||||
@@ -271,7 +253,6 @@ const CredentialsPrompt = ({
|
||||
<Button
|
||||
id={"download-all-button"}
|
||||
label={"Download all access credentials"}
|
||||
className={classes.buttonSpacer}
|
||||
onClick={downloaddAllCredentials}
|
||||
icon={<DownloadIcon />}
|
||||
variant="callAction"
|
||||
@@ -279,7 +260,7 @@ const CredentialsPrompt = ({
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -287,4 +268,4 @@ const CredentialsPrompt = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default withStyles(styles)(CredentialsPrompt);
|
||||
export default CredentialsPrompt;
|
||||
|
||||
@@ -908,13 +908,7 @@ export const modalStyleUtils: any = {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
|
||||
"& button": {
|
||||
marginRight: 10,
|
||||
},
|
||||
"& button:last-child": {
|
||||
marginRight: 0,
|
||||
},
|
||||
gap: 10,
|
||||
},
|
||||
modalFormScrollable: {
|
||||
maxHeight: "calc(100vh - 300px)",
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
|
||||
import React from "react";
|
||||
import { InputBox, SearchIcon } from "mds";
|
||||
import { CSSObject } from "styled-components";
|
||||
|
||||
type SearchBoxProps = {
|
||||
placeholder?: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
overrideClass?: any;
|
||||
sx?: CSSObject;
|
||||
};
|
||||
|
||||
const SearchBox = ({
|
||||
@@ -29,6 +31,7 @@ const SearchBox = ({
|
||||
onChange,
|
||||
overrideClass,
|
||||
value,
|
||||
sx,
|
||||
}: SearchBoxProps) => {
|
||||
return (
|
||||
<InputBox
|
||||
@@ -45,6 +48,7 @@ const SearchBox = ({
|
||||
style={{ width: 16, height: 16, marginTop: 5, marginRight: 5 }}
|
||||
/>
|
||||
}
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React from "react";
|
||||
|
||||
import { DialogContentText } from "@mui/material";
|
||||
import React, { Fragment } from "react";
|
||||
import { ConfirmDeleteIcon } from "mds";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import useApi from "../../../screens/Console/Common/Hooks/useApi";
|
||||
import ConfirmDialog from "../../../screens/Console/Common/ModalWrapper/ConfirmDialog";
|
||||
import { ConfirmDeleteIcon } from "mds";
|
||||
import { setErrorSnackMessage } from "../../../systemSlice";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
@@ -60,10 +59,10 @@ const DeleteMultipleSAs = ({
|
||||
onConfirm={onConfirmDelete}
|
||||
onClose={onClose}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
<Fragment>
|
||||
Are you sure you want to delete the selected {selectedSAs.length}{" "}
|
||||
Access Keys?{" "}
|
||||
</DialogContentText>
|
||||
</Fragment>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user